static int vbf_beresp2obj(struct busyobj *bo) { unsigned l, l2; char *b; uint8_t *bp; struct vsb *vary = NULL; int varyl = 0; l = 0; /* Create Vary instructions */ if (!(bo->fetch_objcore->flags & OC_F_PRIVATE)) { varyl = VRY_Create(bo, &vary); if (varyl > 0) { AN(vary); assert(varyl == VSB_len(vary)); l += PRNDUP((intptr_t)varyl); } else if (varyl < 0) { /* * Vary parse error * Complain about it, and make this a pass. */ VSLb(bo->vsl, SLT_Error, "Illegal 'Vary' header from backend, " "making this a pass."); bo->uncacheable = 1; AZ(vary); } else /* No vary */ AZ(vary); } l2 = http_EstimateWS(bo->beresp, bo->uncacheable ? HTTPH_R_PASS : HTTPH_A_INS); l += l2; if (bo->uncacheable) bo->fetch_objcore->flags |= OC_F_PASS; if (!vbf_allocobj(bo, l)) return (-1); if (vary != NULL) { b = ObjSetattr(bo->wrk, bo->fetch_objcore, OA_VARY, varyl, VSB_data(vary)); VSB_delete(vary); } AZ(ObjSetU32(bo->wrk, bo->fetch_objcore, OA_VXID, VXID(bo->vsl->wid))); /* for HTTP_Encode() VSLH call */ bo->beresp->logtag = SLT_ObjMethod; /* Filter into object */ bp = ObjSetattr(bo->wrk, bo->fetch_objcore, OA_HEADERS, l2, NULL); AN(bp); HTTP_Encode(bo->beresp, bp, l2, bo->uncacheable ? HTTPH_R_PASS : HTTPH_A_INS); if (http_GetHdr(bo->beresp, H_Last_Modified, &b)) AZ(ObjSetDouble(bo->wrk, bo->fetch_objcore, OA_LASTMODIFIED, VTIM_parse(b))); else AZ(ObjSetDouble(bo->wrk, bo->fetch_objcore, OA_LASTMODIFIED, floor(bo->fetch_objcore->exp.t_origin))); return (0); }
static enum fetch_step vbf_stp_fetch(struct worker *wrk, struct busyobj *bo) { struct http *hp, *hp2; char *b; uint16_t nhttp; unsigned l; struct vsb *vary = NULL; int varyl = 0; struct object *obj; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); assert(wrk->handling == VCL_RET_DELIVER); /* * The VCL variables beresp.do_g[un]zip tells us how we want the * object processed before it is stored. * * The backend Content-Encoding header tells us what we are going * to receive, which we classify in the following three classes: * * "Content-Encoding: gzip" --> object is gzip'ed. * no Content-Encoding --> object is not gzip'ed. * anything else --> do nothing wrt gzip * * XXX: BS_NONE/cl==0 should avoid gzip/gunzip */ /* We do nothing unless the param is set */ if (!cache_param->http_gzip_support) bo->do_gzip = bo->do_gunzip = 0; bo->is_gzip = http_HdrIs(bo->beresp, H_Content_Encoding, "gzip"); bo->is_gunzip = !http_GetHdr(bo->beresp, H_Content_Encoding, NULL); /* It can't be both */ assert(bo->is_gzip == 0 || bo->is_gunzip == 0); /* We won't gunzip unless it is gzip'ed */ if (bo->do_gunzip && !bo->is_gzip) bo->do_gunzip = 0; /* If we do gunzip, remove the C-E header */ if (bo->do_gunzip) http_Unset(bo->beresp, H_Content_Encoding); /* We wont gzip unless it is ungziped */ if (bo->do_gzip && !bo->is_gunzip) bo->do_gzip = 0; /* If we do gzip, add the C-E header */ if (bo->do_gzip) http_SetHeader(bo->beresp, "Content-Encoding: gzip"); /* But we can't do both at the same time */ assert(bo->do_gzip == 0 || bo->do_gunzip == 0); /* ESI takes precedence and handles gzip/gunzip itself */ if (bo->do_esi) bo->vfp = &vfp_esi; else if (bo->do_gunzip) bo->vfp = &vfp_gunzip; else if (bo->do_gzip) bo->vfp = &vfp_gzip; else if (bo->is_gzip) bo->vfp = &vfp_testgzip; if (bo->fetch_objcore->flags & OC_F_PRIVATE) AN(bo->uncacheable); /* No reason to try streaming a non-existing body */ if (bo->htc.body_status == BS_NONE) bo->do_stream = 0; l = 0; /* Create Vary instructions */ if (!(bo->fetch_objcore->flags & OC_F_PRIVATE)) { varyl = VRY_Create(bo, &vary); if (varyl > 0) { AN(vary); assert(varyl == VSB_len(vary)); l += varyl; } else if (varyl < 0) { /* * Vary parse error * Complain about it, and make this a pass. */ VSLb(bo->vsl, SLT_Error, "Illegal 'Vary' header from backend, " "making this a pass."); bo->uncacheable = 1; AZ(vary); } else /* No vary */ AZ(vary); } l += http_EstimateWS(bo->beresp, bo->uncacheable ? HTTPH_R_PASS : HTTPH_A_INS, &nhttp); if (bo->uncacheable) bo->fetch_objcore->flags |= OC_F_PASS; if (bo->exp.ttl < cache_param->shortlived || bo->uncacheable == 1) bo->storage_hint = TRANSIENT_STORAGE; AZ(bo->stats); bo->stats = &wrk->stats; AN(bo->fetch_objcore); obj = STV_NewObject(bo, bo->storage_hint, l, nhttp); if (obj == NULL) { /* * Try to salvage the transaction by allocating a * shortlived object on Transient storage. */ if (bo->exp.ttl > cache_param->shortlived) bo->exp.ttl = cache_param->shortlived; bo->exp.grace = 0.0; bo->exp.keep = 0.0; obj = STV_NewObject(bo, TRANSIENT_STORAGE, l, nhttp); } bo->stats = NULL; if (obj == NULL) { (void)VFP_Error(bo, "Could not get storage"); VDI_CloseFd(&bo->vbc); return (F_STP_DONE); } CHECK_OBJ_NOTNULL(obj, OBJECT_MAGIC); bo->storage_hint = NULL; AZ(bo->fetch_obj); bo->fetch_obj = obj; if (bo->do_gzip || (bo->is_gzip && !bo->do_gunzip)) obj->gziped = 1; if (vary != NULL) { obj->vary = (void *)WS_Copy(obj->http->ws, VSB_data(vary), varyl); AN(obj->vary); VRY_Validate(obj->vary); VSB_delete(vary); } obj->vxid = bo->vsl->wid; obj->response = bo->err_code; WS_Assert(bo->ws_o); /* Filter into object */ hp = bo->beresp; hp2 = obj->http; hp2->logtag = HTTP_Obj; http_FilterResp(hp, hp2, bo->uncacheable ? HTTPH_R_PASS : HTTPH_A_INS); http_CopyHome(hp2); if (http_GetHdr(hp, H_Last_Modified, &b)) obj->last_modified = VTIM_parse(b); else obj->last_modified = floor(bo->exp.entered); assert(WRW_IsReleased(wrk)); /* * Ready to fetch the body */ assert(bo->refcount >= 1); if (!(bo->fetch_obj->objcore->flags & OC_F_PRIVATE)) { EXP_Insert(obj); AN(obj->objcore->ban); } AZ(bo->ws_o->overflow); if (bo->do_stream) HSH_Unbusy(&wrk->stats, obj->objcore); if (bo->vfp == NULL) bo->vfp = &VFP_nop; assert(bo->state == BOS_REQ_DONE); VBO_setstate(bo, BOS_FETCHING); V1F_fetch_body(wrk, bo); if (!bo->do_stream) HSH_Unbusy(&wrk->stats, obj->objcore); HSH_Complete(obj->objcore); assert(bo->refcount >= 1); if (bo->state != BOS_FAILED) VBO_setstate(bo, BOS_FINISHED); VSLb(bo->vsl, SLT_Debug, "YYY REF %d %d", bo->refcount, bo->fetch_obj->objcore->refcnt); return (F_STP_DONE); }
void parse_string(char *buf, const struct cmds *cmd, void *priv, struct vtclog *vl) { char *token_s[MAX_TOKENS], *token_e[MAX_TOKENS]; struct vsb *token_exp[MAX_TOKENS]; char *p, *q, *f; int nest_brace; int tn; const struct cmds *cp; assert(buf != NULL); for (p = buf; *p != '\0'; p++) { if (vtc_error || vtc_stop) break; /* Start of line */ if (isspace(*p)) continue; if (*p == '#') { for (; *p != '\0' && *p != '\n'; p++) ; if (*p == '\0') break; continue; } /* First content on line, collect tokens */ tn = 0; f = p; while (*p != '\0') { assert(tn < MAX_TOKENS); if (*p == '\n') { /* End on NL */ break; } if (isspace(*p)) { /* Inter-token whitespace */ p++; continue; } if (*p == '\\' && p[1] == '\n') { /* line-cont */ p += 2; continue; } if (*p == '"') { /* quotes */ token_s[tn] = ++p; q = p; for (; *p != '\0'; p++) { if (*p == '"') break; if (*p == '\\') { p += VAV_BackSlash(p, q) - 1; q++; } else { if (*p == '\n') vtc_log(vl, 0, "Unterminated quoted string in line: %*.*s", (int)(p - f), (int)(p - f), f); assert(*p != '\n'); *q++ = *p; } } token_e[tn++] = q; p++; } else if (*p == '{') { /* Braces */ nest_brace = 0; token_s[tn] = p + 1; for (; *p != '\0'; p++) { if (*p == '{') nest_brace++; else if (*p == '}') { if (--nest_brace == 0) break; } } assert(*p == '}'); token_e[tn++] = p++; } else { /* other tokens */ token_s[tn] = p; for (; *p != '\0' && !isspace(*p); p++) ; token_e[tn++] = p; } } assert(tn < MAX_TOKENS); token_s[tn] = NULL; for (tn = 0; token_s[tn] != NULL; tn++) { token_exp[tn] = NULL; AN(token_e[tn]); /*lint !e771 */ *token_e[tn] = '\0'; /*lint !e771 */ if (NULL == strstr(token_s[tn], "${")) continue; token_exp[tn] = macro_expand(vl, token_s[tn]); if (vtc_error) return; token_s[tn] = VSB_data(token_exp[tn]); token_e[tn] = strchr(token_s[tn], '\0'); } for (cp = cmd; cp->name != NULL; cp++) if (!strcmp(token_s[0], cp->name)) break; if (cp->name == NULL) { vtc_log(vl, 0, "Unknown command: \"%s\"", token_s[0]); return; } vtc_log(vl, 3, "%s", token_s[0]); assert(cp->cmd != NULL); cp->cmd(token_s, priv, cmd, vl); } }
static void pan_ic(const char *func, const char *file, int line, const char *cond, int err, int xxx) { const char *q; const struct sess *sp; AZ(pthread_mutex_lock(&panicstr_mtx)); /* Won't be released, we're going to die anyway */ switch(xxx) { case 3: VSB_printf(pan_vsp, "Wrong turn at %s:%d:\n%s\n", file, line, cond); break; case 2: VSB_printf(pan_vsp, "Panic from VCL:\n %s\n", cond); break; case 1: VSB_printf(pan_vsp, "Missing errorhandling code in %s(), %s line %d:\n" " Condition(%s) not true.", func, file, line, cond); break; default: case 0: VSB_printf(pan_vsp, "Assert error in %s(), %s line %d:\n" " Condition(%s) not true.\n", func, file, line, cond); break; } if (err) VSB_printf(pan_vsp, "errno = %d (%s)\n", err, strerror(err)); q = THR_GetName(); if (q != NULL) VSB_printf(pan_vsp, "thread = (%s)\n", q); VSB_printf(pan_vsp, "ident = %s,%s\n", VSB_data(vident) + 1, WAIT_GetName()); pan_backtrace(); if (!(cache_param->diag_bitmap & 0x2000)) { sp = THR_GetSession(); if (sp != NULL) pan_sess(sp); } VSB_printf(pan_vsp, "\n"); VSB_bcat(pan_vsp, "", 1); /* NUL termination */ if (cache_param->diag_bitmap & 0x4000) (void)fputs(heritage.panic_str, stderr); if (cache_param->diag_bitmap & 0x1000) exit(4); else abort(); }
static void pan_ic(const char *func, const char *file, int line, const char *cond, int err, int xxx) { const char *q; const struct sess *sp; AZ(pthread_mutex_lock(&panicstr_mtx)); /* Won't be released, we're going to die anyway */ switch(xxx) { case 3: VSB_printf(vsp, "Wrong turn at %s:%d:\n%s\n", file, line, cond); break; case 2: VSB_printf(vsp, "Panic from VCL:\n %s\n", cond); break; case 1: VSB_printf(vsp, "Missing errorhandling code in %s(), %s line %d:\n" " Condition(%s) not true.", func, file, line, cond); break; default: case 0: VSB_printf(vsp, "Assert error in %s(), %s line %d:\n" " Condition(%s) not true.\n", func, file, line, cond); break; } if (err) VSB_printf(vsp, "errno = %d (%s)\n", err, strerror(err)); q = THR_GetName(); if (q != NULL) VSB_printf(vsp, "thread = (%s)\n", q); VSB_printf(vsp, "ident = %s,%s\n", VSB_data(vident) + 1, VCA_waiter_name()); pan_backtrace(); if (!(params->diag_bitmap & 0x2000)) { sp = THR_GetSession(); if (sp != NULL) pan_sess(sp); } VSB_printf(vsp, "\n"); VSB_bcat(vsp, "", 1); /* NUL termination */ if (params->diag_bitmap & 0x4000) (void)fputs(VSM_head->panicstr, stderr); #ifdef HAVE_ABORT2 if (params->diag_bitmap & 0x8000) { void *arg[1]; char *p; for (p = VSM_head->panicstr; *p; p++) if (*p == '\n') *p = ' '; arg[0] = VSM_head->panicstr; abort2(VSM_head->panicstr, 1, arg); } #endif if (params->diag_bitmap & 0x1000) exit(4); else abort(); }
static int vbf_beresp2obj(struct busyobj *bo) { unsigned l; char *b; struct vsb *vary = NULL; int varyl = 0; uint16_t nhttp; struct object *obj; struct http *hp, *hp2; l = 0; /* Create Vary instructions */ if (!(bo->fetch_objcore->flags & OC_F_PRIVATE)) { varyl = VRY_Create(bo, &vary); if (varyl > 0) { AN(vary); assert(varyl == VSB_len(vary)); l += varyl; } else if (varyl < 0) { /* * Vary parse error * Complain about it, and make this a pass. */ VSLb(bo->vsl, SLT_Error, "Illegal 'Vary' header from backend, " "making this a pass."); bo->uncacheable = 1; AZ(vary); } else /* No vary */ AZ(vary); } l += http_EstimateWS(bo->beresp, bo->uncacheable ? HTTPH_R_PASS : HTTPH_A_INS, &nhttp); if (bo->uncacheable) bo->fetch_objcore->flags |= OC_F_PASS; obj = vbf_allocobj(bo, l, nhttp); if (obj == NULL) return (-1); CHECK_OBJ_NOTNULL(obj, OBJECT_MAGIC); AZ(bo->fetch_obj); bo->fetch_obj = obj; if (vary != NULL) { obj->vary = (void *)WS_Copy(obj->http->ws, VSB_data(vary), varyl); AN(obj->vary); (void)VRY_Validate(obj->vary); VSB_delete(vary); } obj->vxid = bo->vsl->wid; WS_Assert(bo->ws_o); /* Filter into object */ hp = bo->beresp; hp2 = obj->http; hp2->logtag = SLT_ObjMethod; http_FilterResp(hp, hp2, bo->uncacheable ? HTTPH_R_PASS : HTTPH_A_INS); http_CopyHome(hp2); if (http_GetHdr(hp, H_Last_Modified, &b)) obj->last_modified = VTIM_parse(b); else obj->last_modified = floor(bo->exp.t_origin); return (0); }
static void varnish_launch(struct varnish *v) { struct vsb *vsb, *vsb1; int i, nfd, nap; struct vss_addr **ap; char abuf[128], pbuf[128]; struct pollfd fd[2]; enum VCLI_status_e u; char *r; v->vd = VSM_New(); /* Create listener socket */ nap = VSS_resolve("127.0.0.1", "0", &ap); AN(nap); v->cli_fd = VSS_listen(ap[0], 1); VTCP_myname(v->cli_fd, abuf, sizeof abuf, pbuf, sizeof pbuf); AZ(VSB_finish(v->args)); vtc_log(v->vl, 2, "Launch"); vsb = VSB_new_auto(); AN(vsb); VSB_printf(vsb, "cd ${pwd} &&"); VSB_printf(vsb, " ${varnishd} -d -d -n %s", v->workdir); VSB_printf(vsb, " -l 10m,1m,-"); VSB_printf(vsb, " -p auto_restart=off"); VSB_printf(vsb, " -p syslog_cli_traffic=off"); VSB_printf(vsb, " -a '%s'", "127.0.0.1:0"); VSB_printf(vsb, " -S %s/_S", v->workdir); VSB_printf(vsb, " -M '%s %s'", abuf, pbuf); VSB_printf(vsb, " -P %s/varnishd.pid", v->workdir); VSB_printf(vsb, " %s", VSB_data(v->storage)); VSB_printf(vsb, " %s", VSB_data(v->args)); AZ(VSB_finish(vsb)); vtc_log(v->vl, 3, "CMD: %s", VSB_data(vsb)); vsb1 = macro_expand(v->vl, VSB_data(vsb)); AN(vsb1); VSB_delete(vsb); vsb = vsb1; vtc_log(v->vl, 3, "CMD: %s", VSB_data(vsb)); AZ(pipe(&v->fds[0])); AZ(pipe(&v->fds[2])); v->pid = fork(); assert(v->pid >= 0); if (v->pid == 0) { assert(dup2(v->fds[0], 0) == 0); assert(dup2(v->fds[3], 1) == 1); assert(dup2(1, 2) == 2); AZ(close(v->fds[0])); AZ(close(v->fds[1])); AZ(close(v->fds[2])); AZ(close(v->fds[3])); for (i = 3; i <getdtablesize(); i++) (void)close(i); AZ(execl("/bin/sh", "/bin/sh", "-c", VSB_data(vsb), (char*)0)); exit(1); } else { vtc_log(v->vl, 3, "PID: %ld", (long)v->pid); } AZ(close(v->fds[0])); AZ(close(v->fds[3])); v->fds[0] = v->fds[2]; v->fds[2] = v->fds[3] = -1; VSB_delete(vsb); AZ(pthread_create(&v->tp, NULL, varnish_thread, v)); AZ(pthread_create(&v->tp_vsl, NULL, varnishlog_thread, v)); /* Wait for the varnish to call home */ memset(fd, 0, sizeof fd); fd[0].fd = v->cli_fd; fd[0].events = POLLIN; fd[1].fd = v->fds[0]; fd[1].events = 0; /* Only care about POLLHUP, which is output-only */ i = poll(fd, 2, 10000); vtc_log(v->vl, 4, "CLIPOLL %d 0x%x 0x%x", i, fd[0].revents, fd[1].revents); if (i == 0) { vtc_log(v->vl, 0, "FAIL timeout waiting for CLI connection"); return; } if (fd[1].revents & POLLHUP) { vtc_log(v->vl, 0, "FAIL debug pipe closed"); return; } if (!(fd[0].revents & POLLIN)) { vtc_log(v->vl, 0, "FAIL CLI connection wait failure"); return; } nfd = accept(v->cli_fd, NULL, NULL); if (nfd < 0) { vtc_log(v->vl, 0, "FAIL no CLI connection accepted"); return; } AZ(close(v->cli_fd)); v->cli_fd = nfd; vtc_log(v->vl, 3, "CLI connection fd = %d", v->cli_fd); assert(v->cli_fd >= 0); /* Receive the banner or auth response */ u = varnish_ask_cli(v, NULL, &r); if (vtc_error) return; if (u != CLIS_AUTH) vtc_log(v->vl, 0, "CLI auth demand expected: %u %s", u, r); bprintf(abuf, "%s/_S", v->workdir); nfd = open(abuf, O_RDONLY); assert(nfd >= 0); assert(sizeof abuf >= CLI_AUTH_RESPONSE_LEN + 7); strcpy(abuf, "auth "); VCLI_AuthResponse(nfd, r, abuf + 5); AZ(close(nfd)); free(r); strcat(abuf, "\n"); u = varnish_ask_cli(v, abuf, &r); if (vtc_error) return; if (u != CLIS_OK) vtc_log(v->vl, 0, "CLI auth command failed: %u %s", u, r); free(r); (void)VSL_Arg(v->vd, 'n', v->workdir); AZ(VSM_Open(v->vd)); }
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_delete(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; } } HSH_DerefBoc(wrk, req->objcore); VSB_delete(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); }
static unsigned int vcl_reply(struct http_request *request, void *data) { struct agent_core_t *core = data; struct vcl_priv_t *vcl; struct http_response *resp; struct ipc_ret_t vret; char id[ID_LEN + 1]; int ret; int status; GET_PRIV(core, vcl); if (request->method == M_GET) { if (!strcmp(request->url, "/vclactive") || !strcmp(request->url,"/vclactive/")) { /* * vcl.list output: * * V3/4 : (active|available|discarded) (refcnt) (name) * V4.1 : (active|available|discarded) (state) \ * (busycnt|) (name) */ ipc_run(vcl->vadmin,&vret,"vcl.list"); if (vret.status == 400) { http_reply(request->connection, 500, vret.answer); } else { char **tp, *tok[5]; char *p, *last; char *line; memset(tok, '\0', sizeof(tok)); for (p = vret.answer, last = NULL; (line = strtok_r(p, "\n", &last)); p = NULL) { if (strncmp("active", line, 6)) continue; last = NULL; for (p = line, tp = tok; tp < &tok[4] && (*tp = strtok_r(p, " ", &last)); p = NULL) { if (**tp != '\0') tp++; } } if (!tok[2] || !tok[3]) { http_reply(request->connection, 500, "No active VCL"); } else { strcpy(vret.answer, tok[3] ? tok[3] : tok[2]); http_reply(request->connection, 200, vret.answer); } } free(vret.answer); return 0; } else if (!strcmp(request->url, "/vcl") || !strcmp(request->url,"/vcl/")) { ipc_run(vcl->vadmin, &vret, "vcl.list"); if (vret.status == 400) { http_reply(request->connection, 500, vret.answer); } else { http_reply(request->connection, 200, vret.answer); } free(vret.answer); return 0; } else if (!strncmp(request->url,"/vcl/",strlen("/vcl/"))) { ipc_run(vcl->vadmin, &vret, "vcl.show %s", request->url + strlen("/vcl/")); if (vret.status == 400) { http_reply(request->connection, 500, vret.answer); } else { http_reply(request->connection, 200, vret.answer); } free(vret.answer); return 0; } else if(!strcmp(request->url, "/vcljson/")) { struct vsb *json; ipc_run(vcl->vadmin, &vret, "vcl.list"); if (vret.status == 400) { http_reply(request->connection, 500, vret.answer); } else { json = vcl_list_json(vret.answer); assert(VSB_finish(json) == 0); resp = http_mkresp(request->connection, 200, NULL); resp->data = VSB_data(json); resp->ndata = VSB_len(json); http_add_header(resp, "Content-Type", "application/json"); send_response(resp); http_free_resp(resp); VSB_clear(json); VSB_delete(json); } free(vret.answer); return 0; } else { http_reply(request->connection, 500, "Invalid VCL-url."); return 0; } } else if (request->method == M_POST) { snprintf(id, sizeof(id), "%ju", (uintmax_t) time(NULL)); status = vcl_store(request, vcl, &vret, core, id); http_reply(request->connection, status, vret.answer); free(vret.answer); return 0; } else if (request->method == M_PUT) { if (!strncmp(request->url,"/vcl/",strlen("/vcl/"))) { if (strlen(request->url) >= 6) { status = vcl_store(request, vcl, &vret, core, request->url + strlen("/vcl/")); http_reply(request->connection, status, vret.answer); free(vret.answer); return 0; } else { http_reply(request->connection, 400, "Bad URL?"); return 0; } } else if (!strncmp(request->url, "/vcldeploy/",strlen("/vcldeploy/"))) { ipc_run(vcl->vadmin, &vret, "vcl.use %s", request->url + strlen("/vcldeploy/")); if (vret.status == 200) { ret = vcl_persist_active(vcl->logger, request->url + strlen("/vcldeploy/"), core); } if (vret.status == 200 && ret) http_reply(request->connection, 500, "Deployed ok, but NOT PERSISTED."); else if (vret.status == 200 && ret == 0) http_reply(request->connection, 200, vret.answer); else http_reply(request->connection, 500, vret.answer); free(vret.answer); return 0; } } else if (request->method == M_DELETE) { if (!strncmp(request->url, "/vcl/", strlen("/vcl/"))) { ipc_run(vcl->vadmin, &vret, "vcl.discard %s", request->url + strlen("/vcl/")); if (vret.status == 400 || vret.status == 106) { http_reply(request->connection, 500, vret.answer); } else { http_reply(request->connection, 200, vret.answer); } free(vret.answer); return 0; } } else { return http_reply(request->connection, 500, "Unknown request?"); } assert("Shouldn't get here" == NULL); return 0; }
static void vcc_ParseHostDef(struct vcc *tl, const struct token *t_be, const char *vgcname) { struct token *t_field; struct token *t_val; struct token *t_host = NULL; struct token *t_port = NULL; struct token *t_hosthdr = NULL; struct fld_spec *fs; struct inifin *ifp; struct vsb *vsb; char *p; unsigned u; double t; fs = vcc_FldSpec(tl, "!host", "?port", "?host_header", "?connect_timeout", "?first_byte_timeout", "?between_bytes_timeout", "?probe", "?max_connections", "?proxy_header", NULL); SkipToken(tl, '{'); vsb = VSB_new_auto(); AN(vsb); tl->fb = vsb; Fb(tl, 0, "\nstatic const struct vrt_backend vgc_dir_priv_%s = {\n", vgcname); Fb(tl, 0, "\t.magic = VRT_BACKEND_MAGIC,\n"); Fb(tl, 0, "\t.vcl_name = \"%.*s", PF(t_be)); Fb(tl, 0, "\",\n"); /* Check for old syntax */ if (tl->t->tok == ID && vcc_IdIs(tl->t, "set")) { VSB_printf(tl->sb, "NB: Backend Syntax has changed:\n" "Remove \"set\" and \"backend\" in front" " of backend fields.\n" ); vcc_ErrToken(tl, tl->t); VSB_printf(tl->sb, " at "); vcc_ErrWhere(tl, tl->t); return; } while (tl->t->tok != '}') { vcc_IsField(tl, &t_field, fs); ERRCHK(tl); if (vcc_IdIs(t_field, "host")) { ExpectErr(tl, CSTR); assert(tl->t->dec != NULL); t_host = tl->t; vcc_NextToken(tl); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "port")) { ExpectErr(tl, CSTR); assert(tl->t->dec != NULL); t_port = tl->t; vcc_NextToken(tl); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "host_header")) { ExpectErr(tl, CSTR); assert(tl->t->dec != NULL); t_hosthdr = tl->t; vcc_NextToken(tl); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "connect_timeout")) { Fb(tl, 0, "\t.connect_timeout = "); vcc_Duration(tl, &t); ERRCHK(tl); Fb(tl, 0, "%g,\n", t); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "first_byte_timeout")) { Fb(tl, 0, "\t.first_byte_timeout = "); vcc_Duration(tl, &t); ERRCHK(tl); Fb(tl, 0, "%g,\n", t); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "between_bytes_timeout")) { Fb(tl, 0, "\t.between_bytes_timeout = "); vcc_Duration(tl, &t); ERRCHK(tl); Fb(tl, 0, "%g,\n", t); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "max_connections")) { u = vcc_UintVal(tl); ERRCHK(tl); SkipToken(tl, ';'); Fb(tl, 0, "\t.max_connections = %u,\n", u); } else if (vcc_IdIs(t_field, "proxy_header")) { t_val = tl->t; u = vcc_UintVal(tl); ERRCHK(tl); if (u != 1 && u != 2) { VSB_printf(tl->sb, ".proxy_header must be 1 or 2\n"); vcc_ErrWhere(tl, t_val); return; } SkipToken(tl, ';'); Fb(tl, 0, "\t.proxy_header = %u,\n", u); } else if (vcc_IdIs(t_field, "probe") && tl->t->tok == '{') { vcc_ParseProbeSpec(tl, NULL, &p); Fb(tl, 0, "\t.probe = &%s,\n", p); ERRCHK(tl); } else if (vcc_IdIs(t_field, "probe") && tl->t->tok == ID) { if (VCC_FindSymbol(tl, tl->t, SYM_PROBE) == NULL) { VSB_printf(tl->sb, "Probe %.*s not found\n", PF(tl->t)); vcc_ErrWhere(tl, tl->t); return; } Fb(tl, 0, "\t.probe = &vgc_probe_%.*s,\n", PF(tl->t)); vcc_AddRef(tl, tl->t, SYM_PROBE); vcc_NextToken(tl); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "probe")) { VSB_printf(tl->sb, "Expected '{' or name of probe, got "); vcc_ErrToken(tl, tl->t); VSB_printf(tl->sb, " at\n"); vcc_ErrWhere(tl, tl->t); return; } else { ErrInternal(tl); return; } } vcc_FieldsOk(tl, fs); ERRCHK(tl); /* Check that the hostname makes sense */ assert(t_host != NULL); Emit_Sockaddr(tl, t_host, t_port); ERRCHK(tl); ExpectErr(tl, '}'); /* We have parsed it all, emit the ident string */ /* Emit the hosthdr field, fall back to .host if not specified */ Fb(tl, 0, "\t.hosthdr = "); if (t_hosthdr != NULL) EncToken(tl->fb, t_hosthdr); else EncToken(tl->fb, t_host); Fb(tl, 0, ",\n"); /* Close the struct */ Fb(tl, 0, "};\n"); vcc_NextToken(tl); tl->fb = NULL; AZ(VSB_finish(vsb)); Fh(tl, 0, "%s", VSB_data(vsb)); VSB_destroy(&vsb); ifp = New_IniFin(tl); VSB_printf(ifp->ini, "\t%s =\n\t VRT_new_backend(ctx, &vgc_dir_priv_%s);", vgcname, vgcname); }
static void mgt_reap_child(void) { int i; int status = 0xffff; struct vsb *vsb; pid_t r = 0; assert(child_pid != -1); /* * Close the CLI connections * This signals orderly shut down to child */ mgt_cli_stop_child(); if (child_cli_out >= 0) closex(&child_cli_out); if (child_cli_in >= 0) closex(&child_cli_in); /* Stop the poker */ if (ev_poker != NULL) { vev_del(mgt_evb, ev_poker); free(ev_poker); } ev_poker = NULL; /* Stop the listener */ if (ev_listen != NULL) { vev_del(mgt_evb, ev_listen); free(ev_listen); ev_listen = NULL; } /* Compose obituary */ vsb = VSB_new_auto(); XXXAN(vsb); /* Wait for child to die */ for (i = 0; i < mgt_param.cli_timeout; i++) { r = waitpid(child_pid, &status, WNOHANG); if (r == child_pid) break; (void)sleep(1); } if (r == 0) { VSB_printf(vsb, "Child (%jd) not dying, killing", (intmax_t)r); /* Kick it Jim... */ if (MGT_FEATURE(FEATURE_NO_COREDUMP)) (void)kill(child_pid, SIGKILL); else (void)kill(child_pid, SIGQUIT); r = waitpid(child_pid, &status, 0); } if (r != child_pid) fprintf(stderr, "WAIT 0x%jx\n", (uintmax_t)r); assert(r == child_pid); MAC_reopen_sockets(NULL); VSB_printf(vsb, "Child (%jd) %s", (intmax_t)r, status ? "died" : "ended"); if (WIFEXITED(status) && WEXITSTATUS(status)) { VSB_printf(vsb, " status=%d", WEXITSTATUS(status)); exit_status |= 0x20; if (WEXITSTATUS(status) == 1) VSC_C_mgt->child_exit = ++static_VSC_C_mgt.child_exit; else VSC_C_mgt->child_stop = ++static_VSC_C_mgt.child_stop; } if (WIFSIGNALED(status)) { VSB_printf(vsb, " signal=%d", WTERMSIG(status)); exit_status |= 0x40; VSC_C_mgt->child_died = ++static_VSC_C_mgt.child_died; } #ifdef WCOREDUMP if (WCOREDUMP(status)) { VSB_printf(vsb, " (core dumped)"); exit_status |= 0x80; VSC_C_mgt->child_dump = ++static_VSC_C_mgt.child_dump; } #endif AZ(VSB_finish(vsb)); MGT_complain(status ? C_ERR : C_INFO, "%s", VSB_data(vsb)); VSB_delete(vsb); /* Dispose of shared memory but evacuate panic messages first */ if (heritage.panic_str[0] != '\0') { mgt_panic_record(r); mgt_SHM_Destroy(1); VSC_C_mgt->child_panic = ++static_VSC_C_mgt.child_panic; } else { mgt_SHM_Destroy(MGT_DO_DEBUG(DBG_VSM_KEEP)); } mgt_SHM_Create(); mgt_SHM_Commit(); if (child_state == CH_RUNNING) child_state = CH_DIED; /* Pick up any stuff lingering on stdout/stderr */ (void)child_listener(NULL, EV_RD); closex(&child_output); VLU_Destroy(child_std_vlu); child_pid = -1; MGT_complain(C_DEBUG, "Child cleanup complete"); if (child_state == CH_DIED && mgt_param.auto_restart) mgt_launch_child(NULL); else if (child_state == CH_DIED) child_state = CH_STOPPED; else if (child_state == CH_STOPPING) child_state = CH_STOPPED; }
static void vcc_ParseHostDef(struct vcc *tl, int serial, const char *vgcname) { struct token *t_field; struct token *t_host = NULL; struct token *t_port = NULL; struct token *t_hosthdr = NULL; unsigned saint = UINT_MAX; struct fld_spec *fs; struct vsb *vsb; unsigned u; double t; Fh(tl, 1, "\n#define VGC_backend_%s %d\n", vgcname, tl->ndirector); fs = vcc_FldSpec(tl, "!host", "?port", "?host_header", "?connect_timeout", "?first_byte_timeout", "?between_bytes_timeout", "?probe", "?max_connections", "?saintmode_threshold", NULL); SkipToken(tl, '{'); vsb = VSB_new_auto(); AN(vsb); tl->fb = vsb; Fb(tl, 0, "\nstatic const struct vrt_backend vgc_dir_priv_%s = {\n", vgcname); Fb(tl, 0, "\t.vcl_name = \"%.*s", PF(tl->t_dir)); if (serial >= 0) Fb(tl, 0, "[%d]", serial); Fb(tl, 0, "\",\n"); /* Check for old syntax */ if (tl->t->tok == ID && vcc_IdIs(tl->t, "set")) { VSB_printf(tl->sb, "NB: Backend Syntax has changed:\n" "Remove \"set\" and \"backend\" in front" " of backend fields.\n" ); vcc_ErrToken(tl, tl->t); VSB_printf(tl->sb, " at "); vcc_ErrWhere(tl, tl->t); return; } while (tl->t->tok != '}') { vcc_IsField(tl, &t_field, fs); ERRCHK(tl); if (vcc_IdIs(t_field, "host")) { ExpectErr(tl, CSTR); assert(tl->t->dec != NULL); t_host = tl->t; vcc_NextToken(tl); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "port")) { ExpectErr(tl, CSTR); assert(tl->t->dec != NULL); t_port = tl->t; vcc_NextToken(tl); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "host_header")) { ExpectErr(tl, CSTR); assert(tl->t->dec != NULL); t_hosthdr = tl->t; vcc_NextToken(tl); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "connect_timeout")) { Fb(tl, 0, "\t.connect_timeout = "); vcc_Duration(tl, &t); ERRCHK(tl); Fb(tl, 0, "%g,\n", t); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "first_byte_timeout")) { Fb(tl, 0, "\t.first_byte_timeout = "); vcc_Duration(tl, &t); ERRCHK(tl); Fb(tl, 0, "%g,\n", t); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "between_bytes_timeout")) { Fb(tl, 0, "\t.between_bytes_timeout = "); vcc_Duration(tl, &t); ERRCHK(tl); Fb(tl, 0, "%g,\n", t); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "max_connections")) { u = vcc_UintVal(tl); ERRCHK(tl); SkipToken(tl, ';'); Fb(tl, 0, "\t.max_connections = %u,\n", u); } else if (vcc_IdIs(t_field, "saintmode_threshold")) { u = vcc_UintVal(tl); /* UINT_MAX == magic number to mark as unset, so * not allowed here. */ if (u == UINT_MAX) { VSB_printf(tl->sb, "Value outside allowed range: "); vcc_ErrToken(tl, tl->t); VSB_printf(tl->sb, " at\n"); vcc_ErrWhere(tl, tl->t); } ERRCHK(tl); saint = u; SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "probe") && tl->t->tok == '{') { Fb(tl, 0, "\t.probe = &vgc_probe__%d,\n", tl->nprobe); vcc_ParseProbeSpec(tl); ERRCHK(tl); } else if (vcc_IdIs(t_field, "probe") && tl->t->tok == ID) { Fb(tl, 0, "\t.probe = &vgc_probe_%.*s,\n", PF(tl->t)); vcc_AddRef(tl, tl->t, SYM_PROBE); vcc_NextToken(tl); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "probe")) { VSB_printf(tl->sb, "Expected '{' or name of probe."); vcc_ErrToken(tl, tl->t); VSB_printf(tl->sb, " at\n"); vcc_ErrWhere(tl, tl->t); return; } else { ErrInternal(tl); return; } } vcc_FieldsOk(tl, fs); ERRCHK(tl); /* Check that the hostname makes sense */ assert(t_host != NULL); if (t_port != NULL) Emit_Sockaddr(tl, t_host, t_port->dec); else Emit_Sockaddr(tl, t_host, "80"); ERRCHK(tl); ExpectErr(tl, '}'); /* We have parsed it all, emit the ident string */ /* Emit the hosthdr field, fall back to .host if not specified */ Fb(tl, 0, "\t.hosthdr = "); if (t_hosthdr != NULL) EncToken(tl->fb, t_hosthdr); else EncToken(tl->fb, t_host); Fb(tl, 0, ",\n"); Fb(tl, 0, "\t.saintmode_threshold = %d,\n",saint); /* Close the struct */ Fb(tl, 0, "};\n"); vcc_NextToken(tl); tl->fb = NULL; AZ(VSB_finish(vsb)); Fh(tl, 0, "%s", VSB_data(vsb)); VSB_delete(vsb); Fi(tl, 0, "\tVRT_init_dir(cli, VCL_conf.director, \"simple\",\n" "\t VGC_backend_%s, &vgc_dir_priv_%s);\n", vgcname, vgcname); Ff(tl, 0, "\tVRT_fini_dir(cli, VGCDIR(%s));\n", vgcname); tl->ndirector++; }
pan_ic(const char *func, const char *file, int line, const char *cond, int err, enum vas_e kind) { const char *q; struct req *req; struct busyobj *bo; AZ(pthread_mutex_lock(&panicstr_mtx)); /* Won't be released, we're going to die anyway */ switch(kind) { case VAS_WRONG: VSB_printf(pan_vsp, "Wrong turn at %s:%d:\n%s\n", file, line, cond); break; case VAS_VCL: VSB_printf(pan_vsp, "Panic from VCL:\n %s\n", cond); break; case VAS_MISSING: VSB_printf(pan_vsp, "Missing errorhandling code in %s(), %s line %d:\n" " Condition(%s) not true.", func, file, line, cond); break; case VAS_INCOMPLETE: VSB_printf(pan_vsp, "Incomplete code in %s(), %s line %d:\n", func, file, line); break; default: case VAS_ASSERT: VSB_printf(pan_vsp, "Assert error in %s(), %s line %d:\n" " Condition(%s) not true.\n", func, file, line, cond); break; } if (err) VSB_printf(pan_vsp, "errno = %d (%s)\n", err, strerror(err)); q = THR_GetName(); if (q != NULL) VSB_printf(pan_vsp, "thread = (%s)\n", q); VSB_printf(pan_vsp, "ident = %s,%s\n", VSB_data(vident) + 1, WAIT_GetName()); pan_backtrace(); if (!FEATURE(FEATURE_SHORT_PANIC)) { req = THR_GetRequest(); if (req != NULL) { pan_req(req); VSL_Flush(req->vsl, 0); } bo = THR_GetBusyobj(); if (bo != NULL) { pan_busyobj(bo); VSL_Flush(bo->vsl, 0); } } VSB_printf(pan_vsp, "\n"); VSB_bcat(pan_vsp, "", 1); /* NUL termination */ if (FEATURE(FEATURE_NO_COREDUMP)) exit(4); else abort(); }
int VRY_Create(struct busyobj *bo, struct vsb **psb) { const char *v, *p, *q, *h, *e; struct vsb *sb, *sbh; unsigned l; int error = 0; CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); CHECK_OBJ_NOTNULL(bo->bereq, HTTP_MAGIC); CHECK_OBJ_NOTNULL(bo->beresp, HTTP_MAGIC); AN(psb); AZ(*psb); /* No Vary: header, no worries */ if (!http_GetHdr(bo->beresp, H_Vary, &v)) return (0); /* For vary matching string */ sb = VSB_new_auto(); AN(sb); /* For header matching strings */ sbh = VSB_new_auto(); AN(sbh); for (p = v; *p; p++) { /* Find next header-name */ if (vct_issp(*p)) continue; for (q = p; *q && !vct_issp(*q) && *q != ','; q++) continue; if (q - p > INT8_MAX) { VSLb(bo->vsl, SLT_Error, "Vary header name length exceeded"); error = 1; break; } /* Build a header-matching string out of it */ VSB_clear(sbh); VSB_printf(sbh, "%c%.*s:%c", (char)(1 + (q - p)), (int)(q - p), p, 0); AZ(VSB_finish(sbh)); if (http_GetHdr(bo->bereq, VSB_data(sbh), &h)) { AZ(vct_issp(*h)); /* Trim trailing space */ e = strchr(h, '\0'); while (e > h && vct_issp(e[-1])) e--; /* Encode two byte length and contents */ l = e - h; if (l > 0xffff - 1) { VSLb(bo->vsl, SLT_Error, "Vary header maximum length exceeded"); error = 1; break; } } else { e = h; l = 0xffff; } VSB_printf(sb, "%c%c", (int)(l >> 8), (int)(l & 0xff)); /* Append to vary matching string */ VSB_bcat(sb, VSB_data(sbh), VSB_len(sbh)); if (e != h) VSB_bcat(sb, h, e - h); while (vct_issp(*q)) q++; if (*q == '\0') break; if (*q != ',') { VSLb(bo->vsl, SLT_Error, "Malformed Vary header"); error = 1; break; } p = q; } if (error) { VSB_delete(sbh); VSB_delete(sb); return (-1); } /* Terminate vary matching string */ VSB_printf(sb, "%c%c%c", 0xff, 0xff, 0); VSB_delete(sbh); AZ(VSB_finish(sb)); *psb = sb; return (VSB_len(sb)); }
vep_do_include(struct vep_state *vep, enum dowhat what) { const char *p, *q, *h; ssize_t l; Debug("DO_INCLUDE(%d)\n", what); if (what == DO_ATTR) { Debug("ATTR (%s) (%s)\n", vep->match_hit->match, VSB_data(vep->attr_vsb)); if (vep->include_src != NULL) { vep_error(vep, "ESI 1.0 <esi:include> " "has multiple src= attributes"); vep->state = VEP_TAGERROR; VSB_delete(vep->attr_vsb); VSB_delete(vep->include_src); vep->attr_vsb = NULL; vep->include_src = NULL; return; } vep->include_src = vep->attr_vsb; return; } assert(what == DO_TAG); if (!vep->emptytag) vep_warn(vep, "ESI 1.0 <esi:include> lacks final '/'"); if (vep->include_src == NULL) { vep_error(vep, "ESI 1.0 <esi:include> lacks src attr"); return; } /* * Strictly speaking, we ought to spit out any piled up skip before * emitting the VEC for the include, but objectively that makes no * difference and robs us of a chance to collapse another skip into * this on so we don't do that. * However, we cannot tolerate any verbatim stuff piling up. * The mark_skip() before calling dostuff should have taken * care of that. Make sure. */ assert(vep->o_wait == 0 || vep->last_mark == SKIP); /* XXX: what if it contains NUL bytes ?? */ p = VSB_data(vep->include_src); l = VSB_len(vep->include_src); h = 0; if (l > 7 && !memcmp(p, "http://", 7)) { h = p + 7; p = strchr(h, '/'); AN(p); Debug("HOST <%.*s> PATH <%s>\n", (int)(p-h),h, p); VSB_printf(vep->vsb, "%c", VEC_INCL); VSB_printf(vep->vsb, "Host: %.*s%c", (int)(p-h), h, 0); } else if (l > 8 && !memcmp(p, "https://", 8)) { if (!FEATURE(FEATURE_ESI_IGNORE_HTTPS)) { vep_warn(vep, "ESI 1.0 <esi:include> with https:// ignored"); vep->state = VEP_TAGERROR; vep->attr_vsb = NULL; vep->include_src = NULL; return; } vep_warn(vep, "ESI 1.0 <esi:include> https:// treated as http://"); h = p + 8; p = strchr(h, '/'); AN(p); VSB_printf(vep->vsb, "%c", VEC_INCL); VSB_printf(vep->vsb, "Host: %.*s%c", (int)(p-h), h, 0); } else if (*p == '/') { VSB_printf(vep->vsb, "%c", VEC_INCL); VSB_printf(vep->vsb, "%c", 0); } else { VSB_printf(vep->vsb, "%c", VEC_INCL); VSB_printf(vep->vsb, "%c", 0); /* Look for the last / before a '?' */ h = NULL; for (q = vep->url; *q && *q != '?'; q++) if (*q == '/') h = q; if (h == NULL) h = q + 1; Debug("INCL:: [%.*s]/[%s]\n", (int)(h - vep->url), vep->url, p); VSB_printf(vep->vsb, "%.*s/", (int)(h - vep->url), vep->url); } l -= (p - VSB_data(vep->include_src)); for (q = p; *q != '\0'; ) { if (*q == '&') { #define R(w,f,r) \ if (q + w <= p + l && !memcmp(q, f, w)) { \ VSB_printf(vep->vsb, "%c", r); \ q += w; \ continue; \ } R(6, "'", '\''); R(6, """, '"'); R(4, "<", '<'); R(4, ">", '>'); R(5, "&", '&'); } VSB_printf(vep->vsb, "%c", *q++); } #undef R VSB_printf(vep->vsb, "%c", 0); VSB_delete(vep->include_src); vep->include_src = NULL; }
static int cnt_fetchbody(struct sess *sp) { int i; struct http *hp, *hp2; char *b; uint16_t nhttp; unsigned l; struct vsb *vary = NULL; int varyl = 0, pass; struct worker *wrk; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); wrk = sp->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC); assert(sp->handling == VCL_RET_HIT_FOR_PASS || sp->handling == VCL_RET_DELIVER); if (wrk->objcore == NULL) { /* This is a pass from vcl_recv */ pass = 1; /* VCL may have fiddled this, but that doesn't help */ wrk->busyobj->exp.ttl = -1.; } else if (sp->handling == VCL_RET_HIT_FOR_PASS) { /* pass from vcl_fetch{} -> hit-for-pass */ /* XXX: the bereq was not filtered pass... */ pass = 1; } else { /* regular object */ pass = 0; } /* * The VCL variables beresp.do_g[un]zip tells us how we want the * object processed before it is stored. * * The backend Content-Encoding header tells us what we are going * to receive, which we classify in the following three classes: * * "Content-Encoding: gzip" --> object is gzip'ed. * no Content-Encoding --> object is not gzip'ed. * anything else --> do nothing wrt gzip * */ /* We do nothing unless the param is set */ if (!cache_param->http_gzip_support) wrk->busyobj->do_gzip = wrk->busyobj->do_gunzip = 0; wrk->busyobj->is_gzip = http_HdrIs(wrk->busyobj->beresp, H_Content_Encoding, "gzip"); wrk->busyobj->is_gunzip = !http_GetHdr(wrk->busyobj->beresp, H_Content_Encoding, NULL); /* It can't be both */ assert(wrk->busyobj->is_gzip == 0 || wrk->busyobj->is_gunzip == 0); /* We won't gunzip unless it is gzip'ed */ if (wrk->busyobj->do_gunzip && !wrk->busyobj->is_gzip) wrk->busyobj->do_gunzip = 0; /* If we do gunzip, remove the C-E header */ if (wrk->busyobj->do_gunzip) http_Unset(wrk->busyobj->beresp, H_Content_Encoding); /* We wont gzip unless it is ungziped */ if (wrk->busyobj->do_gzip && !wrk->busyobj->is_gunzip) wrk->busyobj->do_gzip = 0; /* If we do gzip, add the C-E header */ if (wrk->busyobj->do_gzip) http_SetHeader(wrk, sp->vsl_id, wrk->busyobj->beresp, "Content-Encoding: gzip"); /* But we can't do both at the same time */ assert(wrk->busyobj->do_gzip == 0 || wrk->busyobj->do_gunzip == 0); /* ESI takes precedence and handles gzip/gunzip itself */ if (wrk->busyobj->do_esi) wrk->busyobj->vfp = &vfp_esi; else if (wrk->busyobj->do_gunzip) wrk->busyobj->vfp = &vfp_gunzip; else if (wrk->busyobj->do_gzip) wrk->busyobj->vfp = &vfp_gzip; else if (wrk->busyobj->is_gzip) wrk->busyobj->vfp = &vfp_testgzip; if (wrk->busyobj->do_esi || sp->esi_level > 0) wrk->busyobj->do_stream = 0; if (!sp->wantbody) wrk->busyobj->do_stream = 0; l = http_EstimateWS(wrk->busyobj->beresp, pass ? HTTPH_R_PASS : HTTPH_A_INS, &nhttp); /* Create Vary instructions */ if (wrk->objcore != NULL) { CHECK_OBJ_NOTNULL(wrk->objcore, OBJCORE_MAGIC); vary = VRY_Create(sp, wrk->busyobj->beresp); if (vary != NULL) { varyl = VSB_len(vary); assert(varyl > 0); l += varyl; } } /* * Space for producing a Content-Length: header including padding * A billion gigabytes is enough for anybody. */ l += strlen("Content-Length: XxxXxxXxxXxxXxxXxx") + sizeof(void *); if (wrk->busyobj->exp.ttl < cache_param->shortlived || wrk->objcore == NULL) wrk->storage_hint = TRANSIENT_STORAGE; wrk->obj = STV_NewObject(wrk, wrk->storage_hint, l, nhttp); if (wrk->obj == NULL) { /* * Try to salvage the transaction by allocating a * shortlived object on Transient storage. */ wrk->obj = STV_NewObject(wrk, TRANSIENT_STORAGE, l, nhttp); if (wrk->busyobj->exp.ttl > cache_param->shortlived) wrk->busyobj->exp.ttl = cache_param->shortlived; wrk->busyobj->exp.grace = 0.0; wrk->busyobj->exp.keep = 0.0; } if (wrk->obj == NULL) { sp->err_code = 503; sp->step = STP_ERROR; VDI_CloseFd(wrk, &wrk->busyobj->vbc); VBO_DerefBusyObj(wrk, &wrk->busyobj); return (0); } CHECK_OBJ_NOTNULL(wrk->obj, OBJECT_MAGIC); wrk->storage_hint = NULL; if (wrk->busyobj->do_gzip || (wrk->busyobj->is_gzip && !wrk->busyobj->do_gunzip)) wrk->obj->gziped = 1; if (vary != NULL) { wrk->obj->vary = (void *)WS_Alloc(wrk->obj->http->ws, varyl); AN(wrk->obj->vary); memcpy(wrk->obj->vary, VSB_data(vary), varyl); VRY_Validate(wrk->obj->vary); VSB_delete(vary); } wrk->obj->xid = sp->xid; wrk->obj->response = sp->err_code; WS_Assert(wrk->obj->ws_o); /* Filter into object */ hp = wrk->busyobj->beresp; hp2 = wrk->obj->http; hp2->logtag = HTTP_Obj; http_CopyResp(hp2, hp); http_FilterFields(wrk, sp->vsl_id, hp2, hp, pass ? HTTPH_R_PASS : HTTPH_A_INS); http_CopyHome(wrk, sp->vsl_id, hp2); if (http_GetHdr(hp, H_Last_Modified, &b)) wrk->obj->last_modified = VTIM_parse(b); else wrk->obj->last_modified = floor(wrk->busyobj->exp.entered); assert(WRW_IsReleased(wrk)); /* * If we can deliver a 304 reply, we don't bother streaming. * Notice that vcl_deliver{} could still nuke the headers * that allow the 304, in which case we return 200 non-stream. */ if (wrk->obj->response == 200 && sp->http->conds && RFC2616_Do_Cond(sp)) wrk->busyobj->do_stream = 0; AssertObjCorePassOrBusy(wrk->obj->objcore); if (wrk->busyobj->do_stream) { sp->step = STP_PREPRESP; return (0); } /* Use unmodified headers*/ i = FetchBody(wrk, wrk->obj); http_Setup(wrk->busyobj->bereq, NULL); http_Setup(wrk->busyobj->beresp, NULL); wrk->busyobj->vfp = NULL; assert(WRW_IsReleased(wrk)); AZ(wrk->busyobj->vbc); AN(sp->director); if (i) { HSH_Drop(wrk); VBO_DerefBusyObj(wrk, &wrk->busyobj); AZ(wrk->obj); sp->err_code = 503; sp->step = STP_ERROR; return (0); } if (wrk->obj->objcore != NULL) { EXP_Insert(wrk->obj); AN(wrk->obj->objcore); AN(wrk->obj->objcore->ban); HSH_Unbusy(wrk); } VBO_DerefBusyObj(wrk, &wrk->busyobj); wrk->acct_tmp.fetch++; sp->step = STP_PREPRESP; return (0); }
{ struct vsmwseg *seg; vsmw_lock(); CHECK_OBJ_NOTNULL(vsmw, VSMW_MAGIC); (void)vc; ALLOC_OBJ(seg, VSMWSEG_MAGIC); AN(seg); REPLACE(seg->class, class); seg->len = PRNDUP(payload); VSB_clear(vsmw->vsb); VSB_vprintf(vsmw->vsb, fmt, va); AZ(VSB_finish(vsmw->vsb)); REPLACE(seg->id, VSB_data(vsmw->vsb)); if (vc == NULL) vc = vsmw_newcluster(vsmw, seg->len, class); AN(vc); vc->refs++; seg->cluster = vc; seg->off = vc->next; vc->next += seg->len; assert(vc->next <= vc->len); seg->ptr = seg->off + (char*)vc->ptr; vsmw_addseg(vsmw, seg); vsmw_unlock();
struct vsb * VRY_Create(const struct sess *sp, const struct http *hp) { char *v, *p, *q, *h, *e; struct vsb *sb, *sbh; int l; /* No Vary: header, no worries */ if (!http_GetHdr(hp, H_Vary, &v)) return (NULL); /* For vary matching string */ sb = VSB_new_auto(); AN(sb); /* For header matching strings */ sbh = VSB_new_auto(); AN(sbh); if (*v == ':') { WSP(sp, SLT_Error, "Vary header had extra ':', fix backend"); v++; } for (p = v; *p; p++) { /* Find next header-name */ if (vct_issp(*p)) continue; for (q = p; *q && !vct_issp(*q) && *q != ','; q++) continue; /* Build a header-matching string out of it */ VSB_clear(sbh); VSB_printf(sbh, "%c%.*s:%c", (char)(1 + (q - p)), (int)(q - p), p, 0); AZ(VSB_finish(sbh)); if (http_GetHdr(sp->http, VSB_data(sbh), &h)) { AZ(vct_issp(*h)); /* Trim trailing space */ e = strchr(h, '\0'); while (e > h && vct_issp(e[-1])) e--; /* Encode two byte length and contents */ l = e - h; assert(!(l & ~0xffff)); } else { e = h; l = 0xffff; } VSB_printf(sb, "%c%c", (unsigned)l >> 8, l & 0xff); /* Append to vary matching string */ VSB_bcat(sb, VSB_data(sbh), VSB_len(sbh)); if (e != h) VSB_bcat(sb, h, e - h); while (vct_issp(*q)) q++; if (*q == '\0') break; xxxassert(*q == ','); p = q; } /* Terminate vary matching string */ VSB_printf(sb, "%c%c%c", 0xff, 0xff, 0); VSB_delete(sbh); AZ(VSB_finish(sb)); return(sb); }
const char * BAN_Commit(struct ban_proto *bp) { struct ban *b, *bi; ssize_t ln; double t0; CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC); AN(bp->vsb); if (ban_shutdown) return (ban_error(bp, "Shutting down")); AZ(VSB_finish(bp->vsb)); ln = VSB_len(bp->vsb); assert(ln >= 0); ALLOC_OBJ(b, BAN_MAGIC); if (b == NULL) return (ban_error(bp, ban_build_err_no_mem)); VTAILQ_INIT(&b->objcore); b->spec = malloc(ln + BANS_HEAD_LEN); if (b->spec == NULL) { free(b); return (ban_error(bp, ban_build_err_no_mem)); } b->flags = bp->flags; memset(b->spec, 0, BANS_HEAD_LEN); t0 = VTIM_real(); memcpy(b->spec + BANS_TIMESTAMP, &t0, sizeof t0); b->spec[BANS_FLAGS] = b->flags & 0xff; memcpy(b->spec + BANS_HEAD_LEN, VSB_data(bp->vsb), ln); ln += BANS_HEAD_LEN; vbe32enc(b->spec + BANS_LENGTH, ln); Lck_Lock(&ban_mtx); if (ban_shutdown) { /* We could have raced a shutdown */ Lck_Unlock(&ban_mtx); BAN_Free(b); return (ban_error(bp, "Shutting down")); } bi = VTAILQ_FIRST(&ban_head); VTAILQ_INSERT_HEAD(&ban_head, b, list); ban_start = b; VSC_C_main->bans++; VSC_C_main->bans_added++; VSC_C_main->bans_persisted_bytes += ln; if (b->flags & BANS_FLAG_OBJ) VSC_C_main->bans_obj++; if (b->flags & BANS_FLAG_REQ) VSC_C_main->bans_req++; if (bi != NULL) ban_info_new(b->spec, ln); /* Notify stevedores */ if (cache_param->ban_dups) { /* Hunt down duplicates, and mark them as completed */ for (bi = VTAILQ_NEXT(b, list); bi != NULL; bi = VTAILQ_NEXT(bi, list)) { if (!(bi->flags & BANS_FLAG_COMPLETED) && ban_equal(b->spec, bi->spec)) { ban_mark_completed(bi); VSC_C_main->bans_dups++; } } } if (!(b->flags & BANS_FLAG_REQ)) ban_kick_lurker(); Lck_Unlock(&ban_mtx); BAN_Abandon(bp); return (NULL); }
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); }
char * mgt_VccCompile(struct cli *cli, struct vclprog *vcl, const char *vclname, const char *vclsrc, const char *vclsrcfile, int C_flag) { struct vcc_priv vp; struct vsb *sb; unsigned status; char buf[1024]; FILE *fcs; char **av; int ac; AN(cli); sb = VSB_new_auto(); XXXAN(sb); INIT_OBJ(&vp, VCC_PRIV_MAGIC); vp.vclsrc = vclsrc; vp.vclsrcfile = vclsrcfile; /* * The subdirectory must have a unique name to 100% certain evade * the refcounting semantics of dlopen(3). * * Bad implementations of dlopen(3) think the shlib you are opening * is the same, if the filename is the same as one already opened. * * Sensible implementations do a stat(2) and requires st_ino and * st_dev to also match. * * A correct implementation would run on filesystems which tickle * st_gen, and also insist that be the identical, before declaring * a match. * * Since no correct implementations are known to exist, we are subject * to really interesting races if you do something like: * * (running on 'boot' vcl) * vcl.load foo /foo.vcl * vcl.use foo * few/slow requests * vcl.use boot * vcl.discard foo * vcl.load foo /foo.vcl // dlopen(3) says "same-same" * vcl.use foo * * Because discard of the first 'foo' lingers on non-zero reference * count, and when it finally runs, it trashes the second 'foo' because * dlopen(3) decided they were really the same thing. * * The Best way to reproduce this is to have regexps in the VCL. */ VSB_printf(sb, "vcl_%s.%.9f", vclname, VTIM_real()); AZ(VSB_finish(sb)); vp.dir = strdup(VSB_data(sb)); AN(vp.dir); if (VJ_make_subdir(vp.dir, "VCL", cli->sb)) { free(vp.dir); VSB_destroy(&sb); VCLI_Out(cli, "VCL compilation failed"); VCLI_SetResult(cli, CLIS_PARAM); return (NULL); } VSB_clear(sb); VSB_printf(sb, "%s/%s", vp.dir, VGC_SRC); AZ(VSB_finish(sb)); vp.csrcfile = strdup(VSB_data(sb)); AN(vp.csrcfile); VSB_clear(sb); VSB_printf(sb, "%s/%s", vp.dir, VGC_LIB); AZ(VSB_finish(sb)); vp.libfile = strdup(VSB_data(sb)); AN(vp.csrcfile); VSB_clear(sb); status = mgt_vcc_compile(&vp, sb, C_flag); AZ(VSB_finish(sb)); if (VSB_len(sb) > 0) VCLI_Out(cli, "%s", VSB_data(sb)); VSB_destroy(&sb); if (status || C_flag) { (void)unlink(vp.csrcfile); free(vp.csrcfile); (void)unlink(vp.libfile); free(vp.libfile); (void)rmdir(vp.dir); free(vp.dir); if (status) { VCLI_Out(cli, "VCL compilation failed"); VCLI_SetResult(cli, CLIS_PARAM); } return (NULL); } fcs = fopen(vp.csrcfile, "r"); AN(fcs); while (1) { AN(fgets(buf, sizeof buf, fcs)); if (memcmp(buf, VCC_INFO_PREFIX, strlen(VCC_INFO_PREFIX))) break; av = VAV_Parse(buf, &ac, 0); AN(av); AZ(av[0]); AZ(strcmp(av[1], "/*")); AZ(strcmp(av[ac-1], "*/")); if (!strcmp(av[3], "VCL")) mgt_vcl_depends(vcl, av[4]); else if (!strcmp(av[3], "VMOD")) mgt_vcl_vmod(vcl, av[4], av[5]); else WRONG("Wrong VCCINFO"); VAV_Free(av); } AZ(fclose(fcs)); (void)unlink(vp.csrcfile); free(vp.csrcfile); free(vp.dir); VCLI_Out(cli, "VCL compiled.\n"); return (vp.libfile); }
static char *test_HDR_List(void) { struct hdrt_node *hdrt; struct vsb *sb = VSB_new_auto(); printf("... testing HDR_List()\n"); HDR_List(NULL, sb); VSB_finish(sb); MASSERT(VSB_error(sb) == 0); MASSERT(VSB_len(sb) == 0); VSB_clear(sb); hdrt = HDR_InsertIdx(NULL, "Foo", 4711); HDR_List(hdrt, sb); VSB_finish(sb); MASSERT(VSB_error(sb) == 0); MASSERT(strcasecmp(VSB_data(sb), "Foo,") == 0); #define EXP "Accept,Accept-Charset,Accept-Datetime,Accept-Encoding," \ "Accept-Language," VSB_clear(sb); hdrt = HDR_InsertIdx(NULL, "Accept-Encoding", 1); hdrt = HDR_InsertIdx(hdrt, "Accept", 2); hdrt = HDR_InsertIdx(hdrt, "Accept-Charset", 3); hdrt = HDR_InsertIdx(hdrt, "Accept-Language", 4); hdrt = HDR_InsertIdx(hdrt, "Accept-Datetime", 5); HDR_List(hdrt, sb); VSB_finish(sb); MASSERT(VSB_error(sb) == 0); MASSERT(strcasecmp(VSB_data(sb), EXP) == 0); #undef EXP #define EXP "Content-Disposition,Content-Encoding,Content-Language," \ "Content-Length,Content-Location,Content-MD5,Content-Range," \ "Content-Type," VSB_clear(sb); hdrt = HDR_InsertIdx(NULL, "Content-Disposition", 1); hdrt = HDR_InsertIdx(hdrt, "Content-Encoding", 2); hdrt = HDR_InsertIdx(hdrt, "Content-Language", 3); hdrt = HDR_InsertIdx(hdrt, "Content-Length", 4); hdrt = HDR_InsertIdx(hdrt, "Content-Location", 5); hdrt = HDR_InsertIdx(hdrt, "Content-MD5", 6); hdrt = HDR_InsertIdx(hdrt, "Content-Range", 7); hdrt = HDR_InsertIdx(hdrt, "Content-Type", 8); HDR_List(hdrt, sb); VSB_finish(sb); MASSERT(VSB_error(sb) == 0); MASSERT(strcasecmp(VSB_data(sb), EXP) == 0); #undef EXP #define EXP "X-Csrf-Token,X-Forwarded-For,X-Forwarded-Host,X-Forwarded-Proto," VSB_clear(sb); hdrt = HDR_InsertIdx(NULL, "X-Csrf-Token", 1); hdrt = HDR_InsertIdx(hdrt, "X-Forwarded-For", 2); hdrt = HDR_InsertIdx(hdrt, "X-Forwarded-Host", 3); hdrt = HDR_InsertIdx(hdrt, "X-Forwarded-Proto", 4); HDR_List(hdrt, sb); VSB_finish(sb); MASSERT(VSB_error(sb) == 0); MASSERT(strcasecmp(VSB_data(sb), EXP) == 0); #undef EXP #define EXP "Bereq,Beresp,BerespBody," VSB_clear(sb); hdrt = HDR_InsertIdx(NULL, "Beresp", 0); hdrt = HDR_InsertIdx(hdrt, "BerespBody", 1); hdrt = HDR_InsertIdx(hdrt, "Bereq", 2); HDR_List(hdrt, sb); VSB_finish(sb); MASSERT(VSB_error(sb) == 0); MASSERT(strcasecmp(VSB_data(sb), EXP) == 0); #undef EXP VSB_destroy(&sb); return NULL; }
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 void vcc_ParseProbeSpec(struct vcc *tl, const struct symbol *sym, char **name) { struct fld_spec *fs; struct token *t_field; struct token *t_did = NULL, *t_window = NULL, *t_threshold = NULL; struct token *t_initial = NULL; struct vsb *vsb; char *retval; unsigned window, threshold, initial, status; double t; fs = vcc_FldSpec(tl, "?url", "?request", "?expected_response", "?timeout", "?interval", "?window", "?threshold", "?initial", NULL); SkipToken(tl, '{'); vsb = VSB_new_auto(); AN(vsb); if (sym != NULL) VSB_cat(vsb, sym->rname); else VSB_printf(vsb, "vgc_probe__%d", tl->nprobe++); AZ(VSB_finish(vsb)); retval = TlDup(tl, VSB_data(vsb)); AN(retval); VSB_destroy(&vsb); if (name != NULL) *name = retval; window = 0; threshold = 0; initial = 0; status = 0; Fh(tl, 0, "static const struct vrt_backend_probe %s[] = {{\n", retval); Fh(tl, 0, "\t.magic = VRT_BACKEND_PROBE_MAGIC,\n"); while (tl->t->tok != '}') { vcc_IsField(tl, &t_field, fs); ERRCHK(tl); if (vcc_IdIs(t_field, "url")) { vcc_Redef(tl, "Probe request", &t_did, t_field); ERRCHK(tl); ExpectErr(tl, CSTR); Fh(tl, 0, "\t.url = "); EncToken(tl->fh, tl->t); Fh(tl, 0, ",\n"); vcc_NextToken(tl); } else if (vcc_IdIs(t_field, "request")) { vcc_Redef(tl, "Probe request", &t_did, t_field); ERRCHK(tl); ExpectErr(tl, CSTR); Fh(tl, 0, "\t.request =\n"); while (tl->t->tok == CSTR) { Fh(tl, 0, "\t\t"); EncToken(tl->fh, tl->t); Fh(tl, 0, " \"\\r\\n\"\n"); vcc_NextToken(tl); } Fh(tl, 0, "\t\t\"\\r\\n\",\n"); } else if (vcc_IdIs(t_field, "timeout")) { Fh(tl, 0, "\t.timeout = "); vcc_Duration(tl, &t); ERRCHK(tl); Fh(tl, 0, "%g,\n", t); } else if (vcc_IdIs(t_field, "interval")) { Fh(tl, 0, "\t.interval = "); vcc_Duration(tl, &t); ERRCHK(tl); Fh(tl, 0, "%g,\n", t); } else if (vcc_IdIs(t_field, "window")) { t_window = tl->t; window = vcc_UintVal(tl); ERRCHK(tl); } else if (vcc_IdIs(t_field, "initial")) { t_initial = tl->t; initial = vcc_UintVal(tl); ERRCHK(tl); } else if (vcc_IdIs(t_field, "expected_response")) { status = vcc_UintVal(tl); if (status < 100 || status > 999) { VSB_printf(tl->sb, "Must specify .expected_response with " "exactly three digits " "(100 <= x <= 999)\n"); vcc_ErrWhere(tl, tl->t); return; } ERRCHK(tl); } else if (vcc_IdIs(t_field, "threshold")) { t_threshold = tl->t; threshold = vcc_UintVal(tl); ERRCHK(tl); } else { vcc_ErrToken(tl, t_field); vcc_ErrWhere(tl, t_field); ErrInternal(tl); return; } SkipToken(tl, ';'); } if (t_threshold != NULL || t_window != NULL) { if (t_threshold == NULL && t_window != NULL) { VSB_printf(tl->sb, "Must specify .threshold with .window\n"); vcc_ErrWhere(tl, t_window); return; } else if (t_threshold != NULL && t_window == NULL) { if (threshold > 64) { VSB_printf(tl->sb, "Threshold must be 64 or less.\n"); vcc_ErrWhere(tl, t_threshold); return; } window = threshold + 1; } else if (window > 64) { AN(t_window); VSB_printf(tl->sb, "Window must be 64 or less.\n"); vcc_ErrWhere(tl, t_window); return; } if (threshold > window ) { VSB_printf(tl->sb, "Threshold can not be greater than window.\n"); AN(t_threshold); vcc_ErrWhere(tl, t_threshold); AN(t_window); vcc_ErrWhere(tl, t_window); } Fh(tl, 0, "\t.window = %u,\n", window); Fh(tl, 0, "\t.threshold = %u,\n", threshold); } if (t_initial != NULL) Fh(tl, 0, "\t.initial = %u,\n", initial); else Fh(tl, 0, "\t.initial = ~0U,\n"); if (status > 0) Fh(tl, 0, "\t.exp_status = %u,\n", status); Fh(tl, 0, "}};\n"); SkipToken(tl, '}'); }
static unsigned int vlog_reply(struct http_request *request, void *data) { struct vlog_priv_t *vlog; int ret; char *limit = NULL; char *p; char *tag = NULL; char *itag = NULL; struct agent_core_t *core = data; GET_PRIV(data,vlog); p = next_slash(request->url + 1); assert(vlog->tag==NULL); assert(vlog->answer == NULL); if (p) { limit = strdup(p); assert(limit); char *tmp2 = index(limit,'/'); if (tmp2 && *tmp2) *tmp2 = '\0'; if(!(atoi(limit) > 0)) { free(limit); send_response_fail(request->connection,"Not a number"); return 0; } p = next_slash(p); } if (p) { tag = strdup(p); char *tmp2 = index(tag,'/'); if (tmp2 && *tmp2) *tmp2 = '\0'; p = next_slash(p); } if (p) { itag = strdup(p); char *tmp2 = index(itag,'/'); if (tmp2 && *tmp2) *tmp2 = '\0'; p = next_slash(p); } vlog->answer = VSB_new_auto(); assert(vlog->answer != NULL); vlog->vd = VSM_New(); assert(VSL_Arg(vlog->vd, 'n', core->config->n_arg)); VSL_Setup(vlog->vd); VSL_Arg(vlog->vd, 'd', ""); if (tag) { VSL_Arg(vlog->vd, 'i', tag); if (itag) VSL_Arg(vlog->vd,'I',itag); } else { VSL_Arg(vlog->vd, 'k', limit ? limit : "10"); } if (limit) free(limit); VSB_printf(vlog->answer, "{ \"log\": ["); ret = VSL_Open(vlog->vd, 1); if (ret) { send_response_fail(request->connection, "Error in opening shmlog"); goto cleanup; } if (tag == NULL) { do_order(vlog); } else { do_unorder(vlog); } VSB_printf(vlog->answer, "\n] }\n"); assert(VSB_finish(vlog->answer) == 0); if (VSB_len(vlog->answer) > 1) { struct http_response *resp = http_mkresp(request->connection, 200, NULL); resp->data = VSB_data(vlog->answer); resp->ndata = VSB_len(vlog->answer); http_add_header(resp,"Content-Type","application/json"); send_response2(resp); http_free_resp(resp); } else { send_response_fail(request->connection, "FAIL"); } cleanup: free(tag); free(itag); VSB_clear(vlog->answer); VSB_delete(vlog->answer); VSM_Delete(vlog->vd); vlog->answer = NULL; vlog->entries = 0; return 0; }