static void vxp_quote(const struct vxp *vxp, const char *b, const char *e, int tokoff) { const char *p; char c; assert(b <= e); assert(b >= vxp->b); assert(e <= vxp->e); for (p = vxp->b; p < vxp->e; p++) { if (isspace(*p)) VSB_bcat(vxp->sb, " ", 1); else VSB_bcat(vxp->sb, p, 1); } VSB_putc(vxp->sb, '\n'); for (p = vxp->b; p < vxp->e; p++) { if (p >= b && p < e) { if (p - b == tokoff) c = '^'; else c = '#'; } else c = '-'; VSB_putc(vxp->sb, c); } VSB_putc(vxp->sb, '\n'); }
int vtc_send_proxy(int fd, int version, const struct suckaddr *sac, const struct suckaddr *sas) { struct vsb *vsb; char hc[VTCP_ADDRBUFSIZE]; char pc[VTCP_PORTBUFSIZE]; char hs[VTCP_ADDRBUFSIZE]; char ps[VTCP_PORTBUFSIZE]; int i, len; int proto; AN(sac); AN(sas); assert(version == 1 || version == 2); vsb = VSB_new_auto(); AN(vsb); proto = VSA_Get_Proto(sas); assert(proto == PF_INET6 || proto == PF_INET); if (version == 1) { VSB_bcat(vsb, vpx1_sig, sizeof(vpx1_sig)); if (proto == PF_INET6) VSB_printf(vsb, " TCP6 "); else if (proto == PF_INET) VSB_printf(vsb, " TCP4 "); VTCP_name(sac, hc, sizeof(hc), pc, sizeof(pc)); VTCP_name(sas, hs, sizeof(hs), ps, sizeof(ps)); VSB_printf(vsb, "%s %s %s %s\r\n", hc, hs, pc, ps); } else if (version == 2) { VSB_bcat(vsb, vpx2_sig, sizeof(vpx2_sig)); VSB_putc(vsb, 0x21); if (proto == PF_INET6) { VSB_putc(vsb, 0x21); VSB_putc(vsb, 0x00); VSB_putc(vsb, 0x24); } else if (proto == PF_INET) { VSB_putc(vsb, 0x11); VSB_putc(vsb, 0x00); VSB_putc(vsb, 0x0c); } vpx_enc_addr(vsb, proto, sac); vpx_enc_addr(vsb, proto, sas); vpx_enc_port(vsb, sac); vpx_enc_port(vsb, sas); } else WRONG("Wrong proxy version"); AZ(VSB_finish(vsb)); len = VSB_len(vsb); i = write(fd, VSB_data(vsb), len); VSB_delete(vsb); return (i != len); }
static void ban_add_lump(const struct ban_proto *bp, const void *p, uint32_t len) { uint8_t buf[sizeof len]; buf[0] = 0xff; while (VSB_len(bp->vsb) & PALGN) VSB_putc(bp->vsb, buf[0]); vbe32enc(buf, len); VSB_bcat(bp->vsb, buf, sizeof buf); VSB_bcat(bp->vsb, p, len); }
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"); }
void * vtc_record(struct vtclog *vl, int fd, struct vsb *vsb) { char buf[65536]; struct pollfd fds[1]; int i; (void)VTCP_nonblocking(fd); while (1) { memset(fds, 0, sizeof fds); fds->fd = fd; fds->events = POLLIN; i = poll(fds, 1, 10000); if (i == 0) continue; if (fds->revents & POLLIN) { i = read(fd, buf, sizeof buf - 1); if (i > 0) { if (vsb != NULL) VSB_bcat(vsb, buf, i); buf[i] = '\0'; vtc_dump(vl, 3, "debug", buf, -2); } } if (fds->revents & (POLLERR|POLLHUP)) { vtc_log(vl, 4, "STDOUT poll 0x%x", fds->revents); break; } } return (NULL); }
static void vpx_enc_port(struct vsb *vsb, const struct suckaddr *s) { uint8_t b[2]; vbe16enc(b, (uint16_t)VSA_Port(s)); VSB_bcat(vsb, b, sizeof(b)); }
static int vsf_iter_req_body(void *priv, int flush, const void *ptr, ssize_t len) { (void)flush; VSB_bcat(priv, ptr, len); return (0); }
static int vsf_iter_req_body(struct req *req, void *priv, void *ptr, size_t len) { (void)req; VSB_bcat(priv, ptr, len); return (0); }
/* * 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 vpx_enc_addr(struct vsb *vsb, int proto, const struct suckaddr *s) { const struct sockaddr_in *sin4; const struct sockaddr_in6 *sin6; socklen_t sl; if (proto == PF_INET6) { sin6 = VSA_Get_Sockaddr(s, &sl); //lint !e826 AN(sin6); assert(sl >= sizeof(*sin6)); VSB_bcat(vsb, &sin6->sin6_addr, sizeof(sin6->sin6_addr)); } else { sin4 = VSA_Get_Sockaddr(s, &sl); //lint !e826 AN(sin4); assert(sl >= sizeof(*sin4)); VSB_bcat(vsb, &sin4->sin_addr, sizeof(sin4->sin_addr)); } }
static void vep_emit_verbatim(const struct vep_state *vep, ssize_t l, ssize_t l_crc) { uint8_t buf[4]; vep_emit_len(vep, l, VEC_V1, VEC_V2, VEC_V8); if (vep->dogzip) { vep_emit_len(vep, l_crc, VEC_C1, VEC_C2, VEC_C8); vbe32enc(buf, vep->crc); VSB_bcat(vep->vsb, buf, sizeof buf); } }
/* * Quote a string */ void VSB_quote(struct vsb *s, const char *p, int len, int how) { const char *q; int quote = 0; (void)how; /* For future enhancements */ if (len == -1) len = strlen(p); for (q = p; q < p + len; q++) { if (!isgraph(*q) || *q == '"' || *q == '\\') { quote++; break; } } if (!quote) { (void)VSB_bcat(s, p, len); return; } (void)VSB_putc(s, '"'); for (q = p; q < p + len; q++) { switch (*q) { case ' ': (void)VSB_putc(s, *q); break; case '\\': case '"': (void)VSB_putc(s, '\\'); (void)VSB_putc(s, *q); break; case '\n': if (how & VSB_QUOTE_NONL) (void)VSB_cat(s, "\n"); else (void)VSB_cat(s, "\\n"); break; case '\r': (void)VSB_cat(s, "\\r"); break; case '\t': (void)VSB_cat(s, "\\t"); break; default: if (isgraph(*q)) (void)VSB_putc(s, *q); else (void)VSB_printf(s, "\\%o", *q & 0xff); break; } } (void)VSB_putc(s, '"'); }
static void vep_emit_len(const struct vep_state *vep, ssize_t l, int m8, int m16, int m64) { uint8_t buf[9]; assert(l > 0); if (l < 256) { buf[0] = (uint8_t)m8; buf[1] = (uint8_t)l; assert((ssize_t)buf[1] == l); VSB_bcat(vep->vsb, buf, 2); } else if (l < 65536) { buf[0] = (uint8_t)m16; vbe16enc(buf + 1, (uint16_t)l); assert((ssize_t)vbe16dec(buf + 1) == l); VSB_bcat(vep->vsb, buf, 3); } else { buf[0] = (uint8_t)m64; vbe64enc(buf + 1, l); assert((ssize_t)vbe64dec(buf + 1) == l); VSB_bcat(vep->vsb, buf, 9); } }
static void vep_emit_verbatim(const struct vep_state *vep, ssize_t l, ssize_t l_crc) { uint8_t buf[4]; if (params->esi_syntax & 0x20) { Debug("---> VERBATIM(%jd)\n", (intmax_t)l); } vep_emit_len(vep, l, VEC_V1, VEC_V2, VEC_V8); if (vep->dogzip) { vep_emit_len(vep, l_crc, VEC_C1, VEC_C2, VEC_C8); vbe32enc(buf, vep->crc); VSB_bcat(vep->vsb, buf, sizeof buf); } }
VCL_VOID vmod_synth(const struct vrt_ctx *ctx, VCL_STRING name, VCL_INT len) { CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); assert(ctx->method == VCL_MET_SYNTH || ctx->method == VCL_MET_BACKEND_ERROR); if (name == NULL || len <= 0) { return; } CHECK_OBJ_NOTNULL((struct vsb*)ctx->specific, VSB_MAGIC); VSB_bcat((struct vsb*)ctx->specific, name, len); }
/* * Unquote a string */ const char * VSB_unquote(struct vsb *s, const char *p, int len, int how) { const char *q; char *r; unsigned long u; char c; (void)how; /* For future enhancements */ if (len == -1) len = strlen(p); for (q = p; q < p + len; q++) { if (*q != '\\') { (void)VSB_bcat(s, q, 1); continue; } if (++q >= p + len) return ("Incomplete '\\'-sequence at end of string"); switch(*q) { case 'n': (void)VSB_bcat(s, "\n", 1); continue; case 'r': (void)VSB_bcat(s, "\r", 1); continue; case 't': (void)VSB_bcat(s, "\t", 1); continue; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': errno = 0; u = strtoul(q, &r, 8); if (errno != 0 || (u & ~0xff)) return ("\\ooo sequence out of range"); c = (char)u; (void)VSB_bcat(s, &c, 1); q = r - 1; continue; default: (void)VSB_bcat(s, q, 1); } } return (NULL); }
struct vsb * macro_expand(struct vtclog *vl, const char *text) { struct vsb *vsb; const char *p, *q; char *m; vsb = VSB_new_auto(); AN(vsb); while (*text != '\0') { p = strstr(text, "${"); if (p == NULL) { VSB_cat(vsb, text); break; } VSB_bcat(vsb, text, p - text); q = strchr(p, '}'); if (q == NULL) { VSB_cat(vsb, text); break; } assert(p[0] == '$'); assert(p[1] == '{'); assert(q[0] == '}'); p += 2; m = macro_get(p, q); if (m == NULL) { VSB_delete(vsb); vtc_log(vl, 0, "Macro ${%.*s} not found", (int)(q - p), p); return (NULL); } VSB_printf(vsb, "%s", m); free(m); text = q + 1; } AZ(VSB_finish(vsb)); return (vsb); }
pan_ic(const char *func, const char *file, int line, const char *cond, enum vas_e kind) { const char *q; struct req *req; struct busyobj *bo; struct sigaction sa; int err = errno; AZ(pthread_mutex_lock(&panicstr_mtx)); /* Won't be released, we're going to die anyway */ /* * should we trigger a SIGSEGV while handling a panic, our sigsegv * handler would hide the panic, so we need to reset the handler to * default */ memset(&sa, 0, sizeof sa); sa.sa_handler = SIG_DFL; (void)sigaction(SIGSEGV, &sa, NULL); /* Set SIGABRT back to default so the final abort() has the desired effect */ (void)sigaction(SIGABRT, &sa, NULL); switch(kind) { case VAS_WRONG: VSB_printf(pan_vsb, "Wrong turn at %s:%d:\n%s\n", file, line, cond); break; case VAS_VCL: VSB_printf(pan_vsb, "Panic from VCL:\n %s\n", cond); break; case VAS_MISSING: VSB_printf(pan_vsb, "Missing errorhandling code in %s(), %s line %d:\n" " Condition(%s) not true.", func, file, line, cond); break; case VAS_INCOMPLETE: VSB_printf(pan_vsb, "Incomplete code in %s(), %s line %d:\n", func, file, line); break; default: case VAS_ASSERT: VSB_printf(pan_vsb, "Assert error in %s(), %s line %d:\n" " Condition(%s) not true.\n", func, file, line, cond); break; } if (err) VSB_printf(pan_vsb, "errno = %d (%s)\n", err, strerror(err)); q = THR_GetName(); if (q != NULL) VSB_printf(pan_vsb, "thread = (%s)\n", q); VSB_printf(pan_vsb, "version = %s\n", VCS_version); VSB_printf(pan_vsb, "ident = %s,%s\n", VSB_data(vident) + 1, Waiter_GetName()); pan_backtrace(pan_vsb); if (!FEATURE(FEATURE_SHORT_PANIC)) { req = THR_GetRequest(); if (req != NULL) { pan_req(pan_vsb, req); VSL_Flush(req->vsl, 0); } bo = THR_GetBusyobj(); if (bo != NULL) { pan_busyobj(pan_vsb, bo); VSL_Flush(bo->vsl, 0); } } VSB_printf(pan_vsb, "\n"); VSB_bcat(pan_vsb, "", 1); /* NUL termination */ if (FEATURE(FEATURE_NO_COREDUMP)) exit(4); else abort(); }
struct vsb * VRY_Create(const struct sess *sp, const struct http *hp) { char *v, *p, *q, *h, *e; struct vsb *sb, *sbh; unsigned 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", (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; 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); }
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(); }
void VEP_Parse(struct vep_state *vep, const char *p, size_t l) { const char *e; struct vep_match *vm; int i; CHECK_OBJ_NOTNULL(vep, VEP_MAGIC); assert(l > 0); if (vep->startup) { /* * We must force the GZIP header out as a SKIP string, * otherwise an object starting with <esi:include would * have its GZIP header appear after the included object * (e000026.vtc) */ vep->ver_p = ""; vep->last_mark = SKIP; vep_mark_common(vep, vep->ver_p, VERBATIM); vep->startup = 0; AZ(vep->hack_p); vep->hack_p = p; } vep->ver_p = p; e = p + l; while (p < e) { AN(vep->state); i = e - p; if (i > 10) i = 10; Debug("EP %s %d (%.*s) [%.*s]\n", vep->state, vep->remove, vep->tag_i, vep->tag, i, p); assert(p >= vep->ver_p); /****************************************************** * SECTION A */ if (vep->state == VEP_START) { if (FEATURE(FEATURE_ESI_REMOVE_BOM) && *p == '\xeb') { vep->match = vep_match_bom; vep->state = VEP_MATCH; } else vep->state = VEP_BOM; } else if (vep->state == VEP_BOM) { vep_mark_skip(vep, p); if (FEATURE(FEATURE_ESI_DISABLE_XML_CHECK)) vep->state = VEP_NEXTTAG; else vep->state = VEP_TESTXML; } else if (vep->state == VEP_TESTXML) { /* * If the first non-whitespace char is different * from '<' we assume this is not XML. */ while (p < e && vct_islws(*p)) p++; vep_mark_verbatim(vep, p); if (p < e && *p == '<') { p++; vep->state = VEP_STARTTAG; } else if (p < e && *p == '\xeb') { VSLb(vep->vc->wrk->vsl, SLT_ESI_xmlerror, "No ESI processing, " "first char not '<' but BOM." " (See feature esi_remove_bom)" ); vep->state = VEP_NOTXML; } else if (p < e) { VSLb(vep->vc->wrk->vsl, SLT_ESI_xmlerror, "No ESI processing, " "first char not '<'." " (See feature esi_disable_xml_check)" ); vep->state = VEP_NOTXML; } } else if (vep->state == VEP_NOTXML) { /* * This is not recognized as XML, just skip thru * vfp_esi_end() will handle the rest */ p = e; vep_mark_verbatim(vep, p); /****************************************************** * SECTION B */ } else if (vep->state == VEP_NOTMYTAG) { if (FEATURE(FEATURE_ESI_IGNORE_OTHER_ELEMENTS)) { p++; vep->state = VEP_NEXTTAG; } else { vep->tag_i = 0; while (p < e) { if (*p++ == '>') { vep->state = VEP_NEXTTAG; break; } } } if (p == e && !vep->remove) vep_mark_verbatim(vep, p); } else if (vep->state == VEP_NEXTTAG) { /* * Hunt for start of next tag and keep an eye * out for end of EsiCmt if armed. */ vep->emptytag = 0; vep->endtag = 0; vep->attr = NULL; vep->dostuff = NULL; while (p < e && *p != '<') { if (vep->esicmt_p == NULL) { p++; continue; } if (*p != *vep->esicmt_p) { p++; vep->esicmt_p = vep->esicmt; continue; } if (!vep->remove && vep->esicmt_p == vep->esicmt) vep_mark_verbatim(vep, p); p++; if (*++vep->esicmt_p == '\0') { vep->esi_found = 1; vep->esicmt = NULL; vep->esicmt_p = NULL; /* * The end of the esicmt * should not be emitted. * But the stuff before should */ vep_mark_skip(vep, p); } } if (p < e) { if (!vep->remove) vep_mark_verbatim(vep, p); assert(*p == '<'); p++; vep->state = VEP_STARTTAG; } else if (vep->esicmt_p == vep->esicmt && !vep->remove) vep_mark_verbatim(vep, p); /****************************************************** * SECTION C */ } else if (vep->state == VEP_STARTTAG) { /* * Start of tag, set up match table */ if (p < e) { if (*p == '/') { vep->endtag = 1; p++; } vep->match = vep_match_starttag; vep->state = VEP_MATCH; } } else if (vep->state == VEP_COMMENT) { /* * We are in a comment, find out if it is an * ESI comment or a regular comment */ if (vep->esicmt == NULL) vep->esicmt_p = vep->esicmt = "esi"; while (p < e) { if (*p != *vep->esicmt_p) { vep->esicmt_p = vep->esicmt = NULL; vep->until_p = vep->until = "-->"; vep->until_s = VEP_NEXTTAG; vep->state = VEP_UNTIL; break; } p++; if (*++vep->esicmt_p != '\0') continue; if (vep->remove) vep_error(vep, "ESI 1.0 Nested <!--esi" " element in <esi:remove>"); vep->esicmt_p = vep->esicmt = "-->"; vep->state = VEP_NEXTTAG; vep_mark_skip(vep, p); break; } } else if (vep->state == VEP_CDATA) { /* * Easy: just look for the end of CDATA */ vep->until_p = vep->until = "]]>"; vep->until_s = VEP_NEXTTAG; vep->state = VEP_UNTIL; } else if (vep->state == VEP_ESITAG) { vep->in_esi_tag = 1; vep->esi_found = 1; vep_mark_skip(vep, p); vep->match = vep_match_esi; vep->state = VEP_MATCH; } else if (vep->state == VEP_ESIINCLUDE) { if (vep->remove) { vep_error(vep, "ESI 1.0 <esi:include> element" " nested in <esi:remove>"); vep->state = VEP_TAGERROR; } else if (vep->endtag) { vep_error(vep, "ESI 1.0 </esi:include> illegal end-tag"); vep->state = VEP_TAGERROR; } else { vep->dostuff = vep_do_include; vep->state = VEP_INTAG; vep->attr = vep_match_attr_include; } } else if (vep->state == VEP_ESIREMOVE) { vep->dostuff = vep_do_remove; vep->state = VEP_INTAG; } else if (vep->state == VEP_ESICOMMENT) { if (vep->remove) { vep_error(vep, "ESI 1.0 <esi:comment> element" " nested in <esi:remove>"); vep->state = VEP_TAGERROR; } else if (vep->endtag) { vep_error(vep, "ESI 1.0 </esi:comment> illegal end-tag"); vep->state = VEP_TAGERROR; } else { vep->dostuff = vep_do_comment; vep->state = VEP_INTAG; } } else if (vep->state == VEP_ESIBOGON) { vep_error(vep, "ESI 1.0 <esi:bogus> element"); vep->state = VEP_TAGERROR; /****************************************************** * SECTION D */ } else if (vep->state == VEP_INTAG) { vep->tag_i = 0; while (p < e && vct_islws(*p) && !vep->emptytag) { p++; vep->canattr = 1; } if (p < e && *p == '/' && !vep->emptytag) { p++; vep->emptytag = 1; vep->canattr = 0; } if (p < e && *p == '>') { p++; AN(vep->dostuff); vep_mark_skip(vep, p); vep->dostuff(vep, DO_TAG); vep->in_esi_tag = 0; vep->state = VEP_NEXTTAG; } else if (p < e && vep->emptytag) { vep_error(vep, "XML 1.0 '>' does not follow '/' in tag"); vep->state = VEP_TAGERROR; } else if (p < e && vep->canattr && vct_isxmlnamestart(*p)) { vep->state = VEP_ATTR; } else if (p < e) { vep_error(vep, "XML 1.0 Illegal attribute start char"); vep->state = VEP_TAGERROR; } } else if (vep->state == VEP_TAGERROR) { while (p < e && *p != '>') p++; if (p < e) { p++; vep_mark_skip(vep, p); vep->in_esi_tag = 0; vep->state = VEP_NEXTTAG; } /****************************************************** * SECTION E */ } else if (vep->state == VEP_ATTR) { AZ(vep->attr_delim); if (vep->attr == NULL) { p++; AZ(vep->attr_vsb); vep->state = VEP_SKIPATTR; } else { vep->match = vep->attr; vep->state = VEP_MATCH; } } else if (vep->state == VEP_SKIPATTR) { while (p < e && vct_isxmlname(*p)) p++; if (p < e && *p == '=') { p++; vep->state = VEP_ATTRDELIM; } else if (p < e && *p == '>') { vep->state = VEP_INTAG; } else if (p < e && *p == '/') { vep->state = VEP_INTAG; } else if (p < e && vct_issp(*p)) { vep->state = VEP_INTAG; } else if (p < e) { vep_error(vep, "XML 1.0 Illegal attr char"); vep->state = VEP_TAGERROR; } } else if (vep->state == VEP_ATTRGETVAL) { vep->attr_vsb = VSB_new_auto(); vep->state = VEP_ATTRDELIM; } else if (vep->state == VEP_ATTRDELIM) { AZ(vep->attr_delim); if (*p == '"' || *p == '\'') { vep->attr_delim = *p++; vep->state = VEP_ATTRVAL; } else if (!vct_issp(*p)) { vep->attr_delim = ' '; vep->state = VEP_ATTRVAL; } else { vep_error(vep, "XML 1.0 Illegal attribute delimiter"); vep->state = VEP_TAGERROR; } } else if (vep->state == VEP_ATTRVAL) { while (p < e && *p != '>' && *p != vep->attr_delim && (vep->attr_delim != ' ' || !vct_issp(*p))) { if (vep->attr_vsb != NULL) VSB_bcat(vep->attr_vsb, p, 1); p++; } if (p < e && *p == '>') { vep_error(vep, "XML 1.0 Missing end attribute delimiter"); vep->state = VEP_TAGERROR; vep->attr_delim = 0; if (vep->attr_vsb != NULL) { AZ(VSB_finish(vep->attr_vsb)); VSB_delete(vep->attr_vsb); vep->attr_vsb = NULL; } } else if (p < e) { vep->attr_delim = 0; p++; vep->state = VEP_INTAG; if (vep->attr_vsb != NULL) { AZ(VSB_finish(vep->attr_vsb)); AN(vep->dostuff); vep->dostuff(vep, DO_ATTR); vep->attr_vsb = NULL; } } /****************************************************** * Utility Section */ } else if (vep->state == VEP_MATCH) { /* * Match against a table */ vm = vep_match(vep, p, e); vep->match_hit = vm; if (vm != NULL) { if (vm->match != NULL) p += strlen(vm->match); vep->state = *vm->state; vep->match = NULL; vep->tag_i = 0; } else { memcpy(vep->tag, p, e - p); vep->tag_i = e - p; vep->state = VEP_MATCHBUF; p = e; } } else if (vep->state == VEP_MATCHBUF) { /* * Match against a table while split over input * sections. */ AN(vep->match); do { if (*p == '>') { for (vm = vep->match; vm->match != NULL; vm++) continue; AZ(vm->match); } else { vep->tag[vep->tag_i++] = *p++; vm = vep_match(vep, vep->tag, vep->tag + vep->tag_i); if (vm && vm->match == NULL) { vep->tag_i--; p--; } } } while (vm == NULL && p < e); vep->match_hit = vm; if (vm == NULL) { assert(p == e); } else { vep->state = *vm->state; vep->match = NULL; } } else if (vep->state == VEP_UNTIL) { /* * Skip until we see magic string */ while (p < e) { if (*p++ != *vep->until_p++) { vep->until_p = vep->until; } else if (*vep->until_p == '\0') { vep->state = vep->until_s; break; } } if (p == e && !vep->remove) vep_mark_verbatim(vep, p); } else { Debug("*** Unknown state %s\n", vep->state); INCOMPL(); } } /* * We must always mark up the storage we got, try to do so * in the most efficient way, in particular with respect to * minimizing and limiting use of pending. */ if (p == vep->ver_p) ; else if (vep->in_esi_tag) vep_mark_skip(vep, p); else if (vep->remove) vep_mark_skip(vep, p); else vep_mark_pending(vep, p); }
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, WAIT_GetName()); pan_backtrace(); if (!(cache_param->diag_bitmap & 0x2000)) { sp = THR_GetSession(); if (sp != NULL) pan_sess(sp); } VSB_printf(vsp, "\n"); VSB_bcat(vsp, "", 1); /* NUL termination */ if (cache_param->diag_bitmap & 0x4000) (void)fputs(VSM_head->panicstr, stderr); #ifdef HAVE_ABORT2 if (cache_param->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 (cache_param->diag_bitmap & 0x1000) exit(4); else abort(); }
/* * Quote a string */ void VSB_quote_pfx(struct vsb *s, const char *pfx, const void *v, int len, int how) { const char *p; const char *q; int quote = 0; int nl = 0; const unsigned char *u, *w; assert(v != NULL); if (len == -1) len = strlen(v); if (len == 0 && (how & VSB_QUOTE_CSTR)) { VSB_printf(s, "%s\"\"", pfx); return; } else if (len == 0) return; VSB_cat(s, pfx); if (how & VSB_QUOTE_HEX) { u = v; for (w = u; w < u + len; w++) if (*w != 0x00) break; VSB_printf(s, "0x"); if (w == u + len && len > 4) { VSB_printf(s, "0...0"); } else { for (w = u; w < u + len; w++) VSB_printf(s, "%02x", *w); } return; } p = v; for (q = p; q < p + len; q++) { if (!isgraph(*q) || *q == '"' || *q == '\\') { quote++; break; } } if (!quote && !(how & (VSB_QUOTE_JSON|VSB_QUOTE_CSTR))) { (void)VSB_bcat(s, p, len); if ((how & (VSB_QUOTE_UNSAFE|VSB_QUOTE_NONL)) && p[len-1] != '\n') (void)VSB_putc(s, '\n'); return; } if (how & VSB_QUOTE_CSTR) (void)VSB_putc(s, '"'); for (q = p; q < p + len; q++) { if (nl) VSB_cat(s, pfx); nl = 0; switch (*q) { case '?': if (how & VSB_QUOTE_CSTR) (void)VSB_putc(s, '\\'); (void)VSB_putc(s, *q); break; case ' ': (void)VSB_putc(s, *q); break; case '\\': case '"': if (!(how & VSB_QUOTE_UNSAFE)) (void)VSB_putc(s, '\\'); (void)VSB_putc(s, *q); break; case '\n': if (how & VSB_QUOTE_CSTR) { (void)VSB_printf(s, "\\n\"\n%s\t\"", pfx); } else if (how & (VSB_QUOTE_NONL|VSB_QUOTE_UNSAFE)) { (void)VSB_printf(s, "\n"); nl = 1; } else { (void)VSB_printf(s, "\\n"); } break; case '\r': (void)VSB_cat(s, "\\r"); break; case '\t': (void)VSB_cat(s, "\\t"); break; case '\v': (void)VSB_cat(s, "\\v"); break; default: /* XXX: Implement VSB_QUOTE_JSON */ if (isgraph(*q)) (void)VSB_putc(s, *q); else if (how & VSB_QUOTE_ESCHEX) (void)VSB_printf(s, "\\x%02x", *q & 0xff); else (void)VSB_printf(s, "\\%03o", *q & 0xff); break; } } if (how & VSB_QUOTE_CSTR) (void)VSB_putc(s, '"'); if ((how & (VSB_QUOTE_NONL|VSB_QUOTE_UNSAFE)) && !nl) (void)VSB_putc(s, '\n'); }
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)); }
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"); }