//lint -e{818} void vtc_log(struct vtclog *vl, int lvl, const char *fmt, ...) { double tx; CHECK_OBJ_NOTNULL(vl, VTCLOG_MAGIC); tx = VTIM_mono() - t0; AZ(pthread_mutex_lock(&vl->mtx)); vl->act = 1; assert(lvl < (int)NLEAD); VSB_clear(vl->vsb); VSB_printf(vl->vsb, "%s %-4s %4.1f ", lead[lvl < 0 ? 1: lvl], vl->id, tx); va_list ap; va_start(ap, fmt); (void)VSB_vprintf(vl->vsb, fmt, ap); va_end(ap); VSB_putc(vl->vsb, '\n'); AZ(VSB_finish(vl->vsb)); vtc_log_emit(vl, lvl); VSB_clear(vl->vsb); vl->act = 0; AZ(pthread_mutex_unlock(&vl->mtx)); if (lvl > 0) return; if (lvl == 0) vtc_error = 1; if (pthread_self() != vtc_thread) pthread_exit(NULL); }
//lint -e{818} void vtc_hexdump(struct vtclog *vl, int lvl, const char *pfx, const unsigned char *str, int len) { int nl = 1; unsigned l; double tx; CHECK_OBJ_NOTNULL(vl, VTCLOG_MAGIC); tx = VTIM_mono() - t0; assert(len >= 0); assert(lvl >= 0); assert(lvl < NLEAD); AZ(pthread_mutex_lock(&vl->mtx)); vl->act = 1; VSB_clear(vl->vsb); if (pfx == NULL) pfx = ""; if (str == NULL) VSB_printf(vl->vsb, "%s %-4s %4.1f %s| (null)", lead[lvl], vl->id, tx, pfx); else { for (l = 0; l < len; l++, str++) { if (l > 512) { VSB_printf(vl->vsb, "..."); break; } if (nl) { VSB_printf(vl->vsb, "%s %-4s %4.1f %s| ", lead[lvl], vl->id, tx, pfx); nl = 0; } VSB_printf(vl->vsb, " %02x", *str); if ((l & 0xf) == 0xf) { VSB_printf(vl->vsb, "\n"); nl = 1; } } } if (!nl) VSB_printf(vl->vsb, "\n"); AZ(VSB_finish(vl->vsb)); vtc_log_emit(vl, lvl); VSB_clear(vl->vsb); vl->act = 0; AZ(pthread_mutex_unlock(&vl->mtx)); if (lvl == 0) { vtc_error = 1; if (pthread_self() != vtc_thread) pthread_exit(NULL); } }
char * mgt_VccCompile(struct cli *cli, const char *vclname, const char *vclsrc, int C_flag) { struct vcc_priv vp; struct vsb *sb; unsigned status; AN(cli); sb = VSB_new_auto(); XXXAN(sb); INIT_OBJ(&vp, VCC_PRIV_MAGIC); vp.src = vclsrc; VSB_printf(sb, "./vcl_%s.c", vclname); AZ(VSB_finish(sb)); vp.srcfile = strdup(VSB_data(sb)); AN(vp.srcfile); VSB_clear(sb); VSB_printf(sb, "./vcl_%s.so", vclname); AZ(VSB_finish(sb)); vp.libfile = strdup(VSB_data(sb)); AN(vp.srcfile); 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_delete(sb); (void)unlink(vp.srcfile); free(vp.srcfile); if (status || C_flag) { (void)unlink(vp.libfile); free(vp.libfile); if (!C_flag) { VCLI_Out(cli, "VCL compilation failed"); VCLI_SetResult(cli, CLIS_PARAM); } return(NULL); } VCLI_Out(cli, "VCL compiled.\n"); return (vp.libfile); }
static void cmd_http_chunkedlen(CMD_ARGS) { unsigned len; unsigned u, v; char buf[16384]; struct http *hp; (void)cmd; (void)vl; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); AN(av[1]); AZ(av[2]); VSB_clear(hp->vsb); len = atoi(av[1]); if (len == 0) { VSB_printf(hp->vsb, "0%s%s", nl, nl); } else { for (u = 0; u < sizeof buf; u++) buf[u] = (u & 7) + '0'; VSB_printf(hp->vsb, "%x%s", len, nl); for (u = 0; u < len; u += v) { v = len - u; if (v > sizeof buf) v = sizeof buf; VSB_bcat(hp->vsb, buf, v); } VSB_printf(hp->vsb, "%s", nl); } http_write(hp, 4, "chunked"); }
static void vbp_build_req(struct vbp_target *vt, const struct vrt_backend_probe *vbp, const struct backend *be) { struct vsb *vsb; vsb = VSB_new_auto(); AN(vsb); VSB_clear(vsb); if (vbp->request != NULL) { VSB_cat(vsb, vbp->request); } else { VSB_printf(vsb, "GET %s HTTP/1.1\r\n", vbp->url != NULL ? vbp->url : "/"); if (be->hosthdr != NULL) VSB_printf(vsb, "Host: %s\r\n", be->hosthdr); VSB_printf(vsb, "Connection: close\r\n"); VSB_printf(vsb, "\r\n"); } AZ(VSB_finish(vsb)); vt->req = strdup(VSB_data(vsb)); AN(vt->req); vt->req_len = VSB_len(vsb); VSB_destroy(&vsb); }
static unsigned int vstat_reply(struct http_request *request, const char *arg, void *data) { struct vstat_priv_t *vstat; struct agent_core_t *core = data; struct http_response *resp; (void)arg; GET_PRIV(core, vstat); if (check_reopen(&vstat->http)) { http_reply(request->connection, 500, "Couldn't open shmlog"); return 0; } do_json(vstat->http.vd, vstat->http.vsb); resp = http_mkresp(request->connection, 200, NULL); resp->data = VSB_data(vstat->http.vsb); resp->ndata = VSB_len(vstat->http.vsb); http_add_header(resp,"Content-Type","application/json"); send_response(resp); http_free_resp(resp); VSB_clear(vstat->http.vsb); return 0; }
static void vsmw_delseg(struct vsmw *vsmw, struct vsmwseg *seg, int fixidx) { char *t = NULL; ssize_t s; int fd; CHECK_OBJ_NOTNULL(vsmw, VSMW_MAGIC); CHECK_OBJ_NOTNULL(seg, VSMWSEG_MAGIC); VTAILQ_REMOVE(&vsmw->segs, seg, list); REPLACE(seg->class, NULL); REPLACE(seg->id, NULL); FREE_OBJ(seg); if (fixidx) { vsmw_mkent(vsmw, vsmw->idx); REPLACE(t, VSB_data(vsmw->vsb)); AN(t); fd = openat(vsmw->vdirfd, t, O_WRONLY|O_CREAT|O_EXCL, vsmw->mode); assert(fd >= 0); vsmw_idx_head(vsmw, fd); VSB_clear(vsmw->vsb); VTAILQ_FOREACH(seg, &vsmw->segs, list) vsmw_fmt_index(vsmw, seg); AZ(VSB_finish(vsmw->vsb)); s = write(fd, VSB_data(vsmw->vsb), VSB_len(vsmw->vsb)); assert(s == VSB_len(vsmw->vsb)); AZ(close(fd)); AZ(renameat(vsmw->vdirfd, t, vsmw->vdirfd, vsmw->idx)); REPLACE(t, NULL); } }
/* * Copy a byte string into an vsb. */ int VSB_bcpy(struct vsb *s, const void *buf, size_t len) { assert_VSB_integrity(s); assert_VSB_state(s, 0); VSB_clear(s); return (VSB_bcat(s, buf, len)); }
static void h_order_finish(struct vlog_priv_t *vlog, int fd) { assert(VSB_finish(vlog->ob[fd]) == 0); if (VSB_len(vlog->ob[fd]) > 1 && VSL_Matched(vlog->vd, vlog->bitmap[fd])) { VSB_printf(vlog->answer,"%s", VSB_data(vlog->ob[fd])); } vlog->bitmap[fd] = 0; VSB_clear(vlog->ob[fd]); }
/* * Copy a string into an vsb. */ int VSB_cpy(struct vsb *s, const char *str) { assert_VSB_integrity(s); assert_VSB_state(s, 0); VSB_clear(s); return (VSB_cat(s, str)); }
/* * Takes unformatted vcl.list as input and returns a vsb with the json * version. The caller must clean up the vsb. */ static struct vsb * vcl_list_json(char *raw) { struct vcl_list tmp; int ret; char *pos; char ref_temp[10]; const char *sep = ""; struct vsb *vsb; vsb = VSB_new_auto(); pos = raw; VSB_printf(vsb,"{\n\t\"vcls\": ["); while (1) { if (pos[30] != ' ') ret = sscanf(pos, "%10s %4s/%4s %6s %s\n", tmp.available, tmp.state, tmp.temp, ref_temp, tmp.name); else ret = sscanf(pos, "%10s %4s/%4s %s\n", tmp.available, tmp.state, tmp.temp, tmp.name); if (ret <= 0) { /* * FIXME: This should go into the logger */ printf("Confused! line: %s\n", pos); VSB_clear(vsb); return (vsb); } assert(ret>0); VSB_printf(vsb, "%s\n" "\t\t{\n" "\t\t\t\"name\": \"%s\",\n" "\t\t\t\"status\": \"%s\",\n" "\t\t\t\"temp\": \"%s\",\n" "\t\t\t\"mode\": \"%s\"\n" "\t\t}", sep, tmp.name, tmp.available, tmp.temp, tmp.state); sep = ","; pos = strstr(pos,"\n"); if (pos == NULL) break; pos += 1; if (pos[0] == '\0' || pos[0] == '\n') break; } VSB_printf(vsb,"\n\t]\n}\n"); return vsb; }
static void cmd_http_chunked(CMD_ARGS) { struct http *hp; (void)cmd; (void)vl; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); AN(av[1]); AZ(av[2]); VSB_clear(hp->vsb); VSB_printf(hp->vsb, "%jx%s%s%s", (uintmax_t)strlen(av[1]), nl, av[1], nl); http_write(hp, 4, "chunked"); }
static void vsmw_addseg(struct vsmw *vsmw, struct vsmwseg *seg) { int fd; ssize_t s; VTAILQ_INSERT_TAIL(&vsmw->segs, seg, list); fd = openat(vsmw->vdirfd, vsmw->idx, O_APPEND | O_WRONLY); assert(fd >= 0); VSB_clear(vsmw->vsb); vsmw_fmt_index(vsmw, seg); AZ(VSB_finish(vsmw->vsb)); s = write(fd, VSB_data(vsmw->vsb), VSB_len(vsmw->vsb)); assert(s == VSB_len(vsmw->vsb)); AZ(close(fd)); }
static void clean_order(struct vlog_priv_t *vlog) { unsigned u; for (u = 0; u < 65536; u++) { if (vlog->ob[u] == NULL) continue; assert(VSB_finish(vlog->ob[u]) == 0); if (VSB_len(vlog->ob[u]) > 1 && VSL_Matched(vlog->vd, vlog->bitmap[u])) { VSB_printf(vlog->answer,"%s\n", VSB_data(vlog->ob[u])); } vlog->flg[u] = 0; vlog->bitmap[u] = 0; VSB_clear(vlog->ob[u]); } }
int mgt_cli_askchild(unsigned *status, char **resp, const char *fmt, ...) { int i, j; va_list ap; unsigned u; if (cli_buf == NULL) { cli_buf = VSB_new_auto(); AN(cli_buf); } else { VSB_clear(cli_buf); } if (resp != NULL) *resp = NULL; if (status != NULL) *status = 0; if (cli_i < 0 || cli_o < 0) { if (status != NULL) *status = CLIS_CANT; return (CLIS_CANT); } va_start(ap, fmt); AZ(VSB_vprintf(cli_buf, fmt, ap)); va_end(ap); AZ(VSB_finish(cli_buf)); i = VSB_len(cli_buf); assert(i > 0 && VSB_data(cli_buf)[i - 1] == '\n'); j = write(cli_o, VSB_data(cli_buf), i); if (j != i) { if (status != NULL) *status = CLIS_COMMS; if (resp != NULL) *resp = strdup("CLI communication error"); MCH_Cli_Fail(); return (CLIS_COMMS); } if (VCLI_ReadResult(cli_i, &u, resp, mgt_param.cli_timeout)) MCH_Cli_Fail(); if (status != NULL) *status = u; return (u == CLIS_OK ? 0 : u); }
int vsl_diag(struct VSL_data *vsl, const char *fmt, ...) { va_list ap; CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC); AN(fmt); if (vsl->diag == NULL) vsl->diag = VSB_new_auto(); AN(vsl->diag); VSB_clear(vsl->diag); va_start(ap, fmt); VSB_vprintf(vsl->diag, fmt, ap); va_end(ap); AZ(VSB_finish(vsl->diag)); return (-1); }
static void cmd_http_txresp(CMD_ARGS) { struct http *hp; const char *proto = "HTTP/1.1"; const char *status = "200"; const char *msg = "OK"; char* body = NULL; (void)cmd; (void)vl; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); ONLY_SERVER(hp, av); AZ(strcmp(av[0], "txresp")); av++; VSB_clear(hp->vsb); for(; *av != NULL; av++) { if (!strcmp(*av, "-proto")) { proto = av[1]; av++; } else if (!strcmp(*av, "-status")) { status = av[1]; av++; } else if (!strcmp(*av, "-msg")) { msg = av[1]; av++; continue; } else break; } VSB_printf(hp->vsb, "%s %s %s%s", proto, status, msg, nl); /* send a "Content-Length: 0" header unless something else happens */ REPLACE(body, ""); av = http_tx_parse_args(av, vl, hp, body); if (*av != NULL) vtc_log(hp->vl, 0, "Unknown http txresp spec: %s\n", *av); http_write(hp, 4, "txresp"); }
static void vsmw_mkent(const struct vsmw *vsmw, const char *pfx) { int fd; uint64_t rn; AN(pfx); while (1) { VSB_clear(vsmw->vsb); VSB_printf(vsmw->vsb, "_.%s", pfx); AZ(VRND_RandomCrypto(&rn, sizeof rn)); VSB_printf(vsmw->vsb, ".%016jx", (uintmax_t)rn); AZ(VSB_finish(vsmw->vsb)); fd = openat(vsmw->vdirfd, VSB_data(vsmw->vsb), O_RDONLY); if (fd < 0 && errno == ENOENT) return; if (fd >= 0) AZ(close(fd)); } }
static unsigned int vcl_json(struct http_request *request, const char *arg, void *data) { struct agent_core_t *core = data; struct vcl_priv_t *vcl; struct ipc_ret_t vret; struct vsb *json; struct http_response *resp; GET_PRIV(core, vcl); assert(STARTS_WITH(request->url, "/vcljson")); assert(request->method == M_GET); if (arg) { http_reply(request->connection, 404, "/vcljson takes no argument"); return (0); } 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); }
static void varnish_vclbackend(struct varnish *v, const char *vcl) { struct vsb *vsb, *vsb2; enum VCLI_status_e u; if (v->cli_fd < 0) varnish_launch(v); if (vtc_error) return; vsb = VSB_new_auto(); AN(vsb); vsb2 = VSB_new_auto(); AN(vsb2); cmd_server_genvcl(vsb2); AZ(VSB_finish(vsb2)); VSB_printf(vsb, "vcl.inline vcl%d << %s\n%s\n%s\n%s\n", ++v->vcl_nbr, NONSENSE, VSB_data(vsb2), vcl, NONSENSE); AZ(VSB_finish(vsb)); u = varnish_ask_cli(v, VSB_data(vsb), NULL); if (u != CLIS_OK) { VSB_delete(vsb); VSB_delete(vsb2); vtc_log(v->vl, 0, "FAIL VCL does not compile"); return; } VSB_clear(vsb); VSB_printf(vsb, "vcl.use vcl%d", v->vcl_nbr); AZ(VSB_finish(vsb)); u = varnish_ask_cli(v, VSB_data(vsb), NULL); assert(u == CLIS_OK); VSB_delete(vsb); VSB_delete(vsb2); }
/* * Takes unformatted vcl.list as input and returns a vsb with the json * version. The caller must clean up the vsb. */ static struct vsb * vcl_list_json(char *raw) { struct vcl_list tmp; int ret; char *pos; struct vsb *vsb; vsb = VSB_new_auto(); pos = raw; VSB_printf(vsb,"{\n\t\"vcls\": [\n"); do { ret = sscanf(pos, "%10s %6s %s\n", tmp.available, tmp.ref, tmp.name); if (ret <= 0) { /* * FIXME: This should go into the logger */ printf("Confused! line: %s\n", pos); VSB_clear(vsb); return vsb; } assert(ret>0); VSB_printf(vsb, "%s{\n" "\t\t\t\"name\": \"%s\",\n" "\t\t\t\"status\": \"%s\",\n" "\t\t\t\"refs\": \"%s\"\n" "\t\t}",pos != raw ? ",\n\t\t" : "\t\t", tmp.name, tmp.available, tmp.ref); pos = strstr(pos,"\n"); if (pos == NULL) break; pos+=1; if (pos[0] == '\0' || pos[0] == '\n') break; } while (1); VSB_printf(vsb,"\n\t]\n}\n"); return vsb; }
/* * Push stats to url. * * Called from different threads due to /push/test/stats */ static int push_stats(struct vstat_priv_t *vstat, struct vstat_thread_ctx_t *ctx) { struct ipc_ret_t vret; int ret = 0; pthread_rwlock_rdlock(&vstat->lck); if (!vstat->push_url || !(*vstat->push_url) || check_reopen(ctx)) { pthread_rwlock_unlock(&vstat->lck); return -1; } do_json(ctx->vd, ctx->vsb); ipc_run(ctx->curl, &vret, "%s\n%s",vstat->push_url, VSB_data(ctx->vsb)); pthread_rwlock_unlock(&vstat->lck); VSB_clear(ctx->vsb); if (vret.status != 200) { logger(ctx->logger,"cURL returned %d: %s", vret.status, vret.answer); ret = -1; } assert(vret.answer); free(vret.answer); return ret; }
static void cmd_http_txreq(CMD_ARGS) { struct http *hp; const char *req = "GET"; const char *url = "/"; const char *proto = "HTTP/1.1"; (void)cmd; (void)vl; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); ONLY_CLIENT(hp, av); AZ(strcmp(av[0], "txreq")); av++; VSB_clear(hp->vsb); for(; *av != NULL; av++) { if (!strcmp(*av, "-url")) { url = av[1]; av++; } else if (!strcmp(*av, "-proto")) { proto = av[1]; av++; } else if (!strcmp(*av, "-req")) { req = av[1]; av++; } else break; } VSB_printf(hp->vsb, "%s %s %s%s", req, url, proto, nl); av = http_tx_parse_args(av, vl, hp, NULL); if (*av != NULL) vtc_log(hp->vl, 0, "Unknown http txreq spec: %s\n", *av); http_write(hp, 4, "txreq"); }
static void varnish_vcl(struct varnish *v, const char *vcl, enum VCLI_status_e expect) { struct vsb *vsb; enum VCLI_status_e u; if (v->cli_fd < 0) varnish_launch(v); if (vtc_error) return; vsb = VSB_new_auto(); AN(vsb); VSB_printf(vsb, "vcl.inline vcl%d << %s\n%s\n%s\n", ++v->vcl_nbr, NONSENSE, vcl, NONSENSE); AZ(VSB_finish(vsb)); u = varnish_ask_cli(v, VSB_data(vsb), NULL); if (u != expect) { VSB_delete(vsb); vtc_log(v->vl, 0, "VCL compilation got %u expected %u", u, expect); return; } if (u == CLIS_OK) { VSB_clear(vsb); VSB_printf(vsb, "vcl.use vcl%d", v->vcl_nbr); AZ(VSB_finish(vsb)); u = varnish_ask_cli(v, VSB_data(vsb), NULL); assert(u == CLIS_OK); } else { vtc_log(v->vl, 2, "VCL compilation failed (as expected)"); } VSB_delete(vsb); }
static const char * ban_error(struct ban_proto *bp, const char *fmt, ...) { va_list ap; CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC); AN(bp->vsb); /* First error is sticky */ if (bp->err == NULL) { if (fmt == ban_build_err_no_mem) { bp->err = ban_build_err_no_mem; } else { /* Record the error message in the vsb */ VSB_clear(bp->vsb); va_start(ap, fmt); (void)VSB_vprintf(bp->vsb, fmt, ap); va_end(ap); AZ(VSB_finish(bp->vsb)); bp->err = VSB_data(bp->vsb); } } return (bp->err); }
static void vbp_build_req(struct vbp_target *vt, const char *hosthdr) { struct vsb *vsb; vsb = VSB_new_auto(); AN(vsb); VSB_clear(vsb); if(vt->probe.request != NULL) { VSB_cat(vsb, vt->probe.request); } else { VSB_printf(vsb, "GET %s HTTP/1.1\r\n", vt->probe.url != NULL ? vt->probe.url : "/"); if (hosthdr != NULL) VSB_printf(vsb, "Host: %s\r\n", hosthdr); VSB_printf(vsb, "Connection: close\r\n"); VSB_printf(vsb, "\r\n"); } AZ(VSB_finish(vsb)); vt->req = strdup(VSB_data(vsb)); AN(vt->req); vt->req_len = VSB_len(vsb); VSB_delete(vsb); }
//lint -e{818} void vtc_dump(struct vtclog *vl, int lvl, const char *pfx, const char *str, int len) { int nl = 1, olen; unsigned l; double tx; CHECK_OBJ_NOTNULL(vl, VTCLOG_MAGIC); tx = VTIM_mono() - t0; assert(lvl >= 0); assert(lvl < NLEAD); AZ(pthread_mutex_lock(&vl->mtx)); vl->act = 1; VSB_clear(vl->vsb); if (pfx == NULL) pfx = ""; if (str == NULL) VSB_printf(vl->vsb, "%s %-4s %4.1f %s(null)\n", lead[lvl], vl->id, tx, pfx); else { olen = len; if (len < 0) len = strlen(str); for (l = 0; l < len; l++, str++) { if (l > 1024 && olen != -2) { VSB_printf(vl->vsb, "..."); break; } if (nl) { VSB_printf(vl->vsb, "%s %-4s %4.1f %s| ", lead[lvl], vl->id, tx, pfx); nl = 0; } if (*str == '\r') VSB_printf(vl->vsb, "\\r"); else if (*str == '\t') VSB_printf(vl->vsb, "\\t"); else if (*str == '\n') { VSB_printf(vl->vsb, "\\n\n"); nl = 1; } else if (*str < 0x20 || *str > 0x7e) VSB_printf(vl->vsb, "\\x%02x", (*str) & 0xff); else VSB_printf(vl->vsb, "%c", *str); } } if (!nl) VSB_printf(vl->vsb, "\n"); AZ(VSB_finish(vl->vsb)); vtc_log_emit(vl, lvl); VSB_clear(vl->vsb); vl->act = 0; AZ(pthread_mutex_unlock(&vl->mtx)); if (lvl == 0) { vtc_error = 1; if (pthread_self() != vtc_thread) pthread_exit(NULL); } }
static void cmd_http_txreq(CMD_ARGS) { struct http *hp; const char *req = "GET"; const char *url = "/"; const char *proto = "HTTP/1.1"; const char *body = NULL; (void)cmd; (void)vl; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); ONLY_CLIENT(hp, av); assert(!strcmp(av[0], "txreq")); av++; VSB_clear(hp->vsb); for(; *av != NULL; av++) { if (!strcmp(*av, "-url")) { url = av[1]; av++; } else if (!strcmp(*av, "-proto")) { proto = av[1]; av++; } else if (!strcmp(*av, "-req")) { req = av[1]; av++; } else break; } VSB_printf(hp->vsb, "%s %s %s%s", req, url, proto, nl); for(; *av != NULL; av++) { if (!strcmp(*av, "-hdr")) { VSB_printf(hp->vsb, "%s%s", av[1], nl); av++; } else break; } for(; *av != NULL; av++) { if (!strcmp(*av, "-body")) { AZ(body); body = av[1]; av++; } else if (!strcmp(*av, "-bodylen")) { AZ(body); body = synth_body(av[1], 0); av++; } else break; } if (*av != NULL) vtc_log(hp->vl, 0, "Unknown http txreq spec: %s\n", *av); if (body != NULL) VSB_printf(hp->vsb, "Content-Length: %ju%s", (uintmax_t)strlen(body), nl); VSB_cat(hp->vsb, nl); if (body != NULL) { VSB_cat(hp->vsb, body); VSB_cat(hp->vsb, nl); } http_write(hp, 4, "txreq"); }
static void cmd_http_txresp(CMD_ARGS) { struct http *hp; const char *proto = "HTTP/1.1"; const char *status = "200"; const char *msg = "Ok"; int bodylen = 0; char *b, *c; char *body = NULL, *nullbody; int nolen = 0; (void)cmd; (void)vl; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); ONLY_SERVER(hp, av); assert(!strcmp(av[0], "txresp")); av++; VSB_clear(hp->vsb); /* send a "Content-Length: 0" header unless something else happens */ REPLACE(body, ""); nullbody = body; for(; *av != NULL; av++) { if (!strcmp(*av, "-proto")) { proto = av[1]; av++; } else if (!strcmp(*av, "-status")) { status = av[1]; av++; } else if (!strcmp(*av, "-msg")) { msg = av[1]; av++; continue; } else break; } VSB_printf(hp->vsb, "%s %s %s%s", proto, status, msg, nl); for(; *av != NULL; av++) { if (!strcmp(*av, "-nolen")) { nolen = 1; } else if (!strcmp(*av, "-hdr")) { VSB_printf(hp->vsb, "%s%s", av[1], nl); av++; } else break; } for(; *av != NULL; av++) { if (!strcmp(*av, "-body")) { assert(body == nullbody); REPLACE(body, av[1]); AN(body); av++; bodylen = strlen(body); for (b = body; *b != '\0'; b++) { if(*b == '\\' && b[1] == '0') { *b = '\0'; for(c = b+1; *c != '\0'; c++) { *c = c[1]; } b++; bodylen--; } } } else if (!strcmp(*av, "-bodylen")) { assert(body == nullbody); body = synth_body(av[1], 0); bodylen = strlen(body); av++; } else if (!strcmp(*av, "-gzipresidual")) { hp->gzipresidual = strtoul(av[1], NULL, 0); av++; } else if (!strcmp(*av, "-gziplevel")) { hp->gziplevel = strtoul(av[1], NULL, 0); av++; } else if (!strcmp(*av, "-gziplen")) { assert(body == nullbody); b = synth_body(av[1], 1); gzip_body(hp, b, &body, &bodylen); VSB_printf(hp->vsb, "Content-Encoding: gzip%s", nl); // vtc_hexdump(hp->vl, 4, "gzip", (void*)body, bodylen); av++; } else if (!strcmp(*av, "-gzipbody")) { assert(body == nullbody); gzip_body(hp, av[1], &body, &bodylen); VSB_printf(hp->vsb, "Content-Encoding: gzip%s", nl); // vtc_hexdump(hp->vl, 4, "gzip", (void*)body, bodylen); av++; } else break; } if (*av != NULL) vtc_log(hp->vl, 0, "Unknown http txresp spec: %s\n", *av); if (body != NULL && !nolen) VSB_printf(hp->vsb, "Content-Length: %d%s", bodylen, nl); VSB_cat(hp->vsb, nl); if (body != NULL) VSB_bcat(hp->vsb, body, bodylen); http_write(hp, 4, "txresp"); }
int VRY_Create(struct busyobj *bo, struct vsb **psb) { 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)); }