/* * Return true if the hp->hd[u] header matches *hdr and the regex *re * matches the content. * * If re is NULL, content is not tested and as long as it's the right * header, a match is returned. */ static int header_http_match(VRT_CTX, const struct http *hp, unsigned u, void *re, const char *hdr) { const char *start; unsigned l; assert(hdr); assert(hp); Tcheck(hp->hd[u]); if (hp->hd[u].b == NULL) return (0); l = hdr[0]; if (!header_http_IsHdr(&hp->hd[u], hdr)) return (0); if (re == NULL) return (1); start = hp->hd[u].b + l; while (*start != '\0' && *start == ' ') start++; if (!*start) return (0); if (VRT_re_match(ctx, start, re)) return (1); return (0); }
void WSLR(struct worker *wrk, enum VSL_tag_e tag, int id, txt t) { unsigned l, mlen; Tcheck(t); mlen = cache_param->shm_reclen; /* Truncate */ l = Tlen(t); if (l > mlen) { l = mlen; t.e = t.b + l; } assert(wrk->wlp < wrk->wle); /* Wrap if necessary */ if (VSL_END(wrk->wlp, l) >= wrk->wle) WSL_Flush(wrk, 1); assert (VSL_END(wrk->wlp, l) < wrk->wle); memcpy(VSL_DATA(wrk->wlp), t.b, l); vsl_hdr(tag, wrk->wlp, l, id); wrk->wlp = VSL_END(wrk->wlp, l); assert(wrk->wlp < wrk->wle); wrk->wlr++; if (cache_param->diag_bitmap & 0x10000) WSL_Flush(wrk, 0); }
const char * http_GetReq(const struct http *hp) { Tcheck(hp->hd[HTTP_HDR_METHOD]); return (hp->hd[HTTP_HDR_METHOD].b); }
static void http_filterfields(struct http *to, const struct http *fm, unsigned how) { unsigned u; CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC); CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); to->nhd = HTTP_HDR_FIRST; to->status = fm->status; for (u = HTTP_HDR_FIRST; u < fm->nhd; u++) { if (fm->hd[u].b == NULL) continue; if (fm->hdf[u] & HDF_FILTER) continue; #define HTTPH(a, b, c) \ if (((c) & how) && http_IsHdr(&fm->hd[u], (b))) \ continue; #include "tbl/http_headers.h" #undef HTTPH Tcheck(fm->hd[u]); if (to->nhd < to->shd) { to->hd[to->nhd] = fm->hd[u]; to->hdf[to->nhd] = 0; to->nhd++; } else { VSC_C_main->losthdr++; VSLbt(to->vsl, SLT_LostHeader, fm->hd[u]); } } }
static int htc_header_complete(txt *t) { const char *p; Tcheck(*t); assert(*t->e == '\0'); /* Skip any leading white space */ for (p = t->b ; isspace(*p); p++) continue; if (*p == '\0') { t->e = t->b; *t->e = '\0'; return (0); } while (1) { p = strchr(p, '\n'); if (p == NULL) return (0); p++; if (*p == '\r') p++; if (*p == '\n') break; } p++; return (p - t->b); }
static void wslr(struct vsl_log *vsl, enum VSL_tag_e tag, int id, txt t) { unsigned l, mlen; Tcheck(t); if (id == -1) id = vsl->wid; mlen = cache_param->shm_reclen; /* Truncate */ l = Tlen(t); if (l > mlen) { l = mlen; t.e = t.b + l; } assert(vsl->wlp < vsl->wle); /* Wrap if necessary */ if (VSL_END(vsl->wlp, l) >= vsl->wle) VSL_Flush(vsl, 1); assert(VSL_END(vsl->wlp, l) < vsl->wle); memcpy(VSL_DATA(vsl->wlp), t.b, l); vsl_hdr(tag, vsl->wlp, l, id); vsl->wlp = VSL_END(vsl->wlp, l); assert(vsl->wlp < vsl->wle); vsl->wlr++; if (cache_param->diag_bitmap & 0x10000) VSL_Flush(vsl, 0); }
static void http_filterfields(struct http *to, const struct http *fm, unsigned how) { unsigned u; CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC); CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); to->nhd = HTTP_HDR_FIRST; to->status = fm->status; for (u = HTTP_HDR_FIRST; u < fm->nhd; u++) { if (fm->hd[u].b == NULL) continue; if (fm->hdf[u] & HDF_FILTER) continue; Tcheck(fm->hd[u]); #define HTTPH(a, b, c) \ if (((c) & how) && http_IsHdr(&fm->hd[u], (b))) \ continue; #include "tbl/http_headers.h" #undef HTTPH assert (to->nhd < to->shd); to->hd[to->nhd] = fm->hd[u]; to->hdf[to->nhd] = 0; http_VSLH(to, to->nhd); to->nhd++; } }
void http_CollectHdr(struct http *hp, const char *hdr) { unsigned u, v, ml, f = 0, x; char *b = NULL, *e = NULL; for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) { while (u < hp->nhd && http_IsHdr(&hp->hd[u], hdr)) { Tcheck(hp->hd[u]); if (f == 0) { /* Found first header, just record the fact */ f = u; break; } if (b == NULL) { /* Found second header, start our collection */ ml = WS_Reserve(hp->ws, 0); b = hp->ws->f; e = b + ml; x = Tlen(hp->hd[f]); if (b + x < e) { memcpy(b, hp->hd[f].b, x); b += x; } else b = e; } AN(b); AN(e); /* Append the Nth header we found */ if (b < e) *b++ = ','; x = Tlen(hp->hd[u]) - *hdr; if (b + x < e) { memcpy(b, hp->hd[u].b + *hdr, x); b += x; } else b = e; /* Shift remaining headers up one slot */ for (v = u; v < hp->nhd - 1; v++) hp->hd[v] = hp->hd[v + 1]; hp->nhd--; } } if (b == NULL) return; AN(e); if (b >= e) { WS_Release(hp->ws, 0); return; } *b = '\0'; hp->hd[f].b = hp->ws->f; hp->hd[f].e = b; WS_ReleaseP(hp->ws, b + 1); }
const char * http_GetReq(const struct http *hp) { CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); Tcheck(hp->hd[HTTP_HDR_METHOD]); return (hp->hd[HTTP_HDR_METHOD].b); }
void http_PutProtocol(const struct http *to, const char *protocol) { http_PutField(to, HTTP_HDR_PROTO, protocol); if (to->hd[HTTP_HDR_PROTO].b == NULL) http_SetH(to, HTTP_HDR_PROTO, "HTTP/1.1"); Tcheck(to->hd[HTTP_HDR_PROTO]); }
void http_PutResponse(const struct http *to, const char *response) { http_PutField(to, HTTP_HDR_RESPONSE, response); if (to->hd[HTTP_HDR_RESPONSE].b == NULL) http_SetH(to, HTTP_HDR_RESPONSE, "Lost Response"); Tcheck(to->hd[HTTP_HDR_RESPONSE]); }
static void http_linkh(const struct http *to, const struct http *fm, unsigned n) { assert(n < HTTP_HDR_FIRST); Tcheck(fm->hd[n]); to->hd[n] = fm->hd[n]; to->hdf[n] = fm->hdf[n]; }
void http_PutProtocol(struct worker *w, unsigned vsl_id, const struct http *to, const char *protocol) { http_PutField(w, vsl_id, to, HTTP_HDR_PROTO, protocol); if (to->hd[HTTP_HDR_PROTO].b == NULL) http_SetH(to, HTTP_HDR_PROTO, "HTTP/1.1"); Tcheck(to->hd[HTTP_HDR_PROTO]); }
void http_PutResponse(struct worker *w, unsigned vsl_id, const struct http *to, const char *response) { http_PutField(w, vsl_id, to, HTTP_HDR_RESPONSE, response); if (to->hd[HTTP_HDR_RESPONSE].b == NULL) http_SetH(to, HTTP_HDR_RESPONSE, "Lost Response"); Tcheck(to->hd[HTTP_HDR_RESPONSE]); }
/* * Returns true if the *hdr header is the one pointed to by *hh. * * FIXME: duplication from varnishd. */ static int header_http_IsHdr(const txt *hh, const char *hdr) { unsigned l; Tcheck(*hh); AN(hdr); l = hdr[0]; assert(l == strlen(hdr + 1)); assert(hdr[l] == ':'); hdr++; return (!strncasecmp(hdr, hh->b, l)); }
static unsigned http_findhdr(const struct http *hp, unsigned l, const char *hdr) { unsigned u; for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) { Tcheck(hp->hd[u]); if (hp->hd[u].e < hp->hd[u].b + l + 1) continue; if (hp->hd[u].b[l] != ':') continue; if (strncasecmp(hdr, hp->hd[u].b, l)) continue; return (u); } return (0); }
static void http_copyheader(struct worker *w, int fd, struct http *to, const struct http *fm, unsigned n) { CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC); CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); assert(n < fm->shd); Tcheck(fm->hd[n]); if (to->nhd < to->shd) { to->hd[to->nhd] = fm->hd[n]; to->hdf[to->nhd] = 0; to->nhd++; } else { VSC_C_main->losthdr++; WSLR(w, SLT_LostHeader, fd, fm->hd[n]); } }
enum htc_status_e HTTP1_Complete(struct http_conn *htc) { char *p; txt *t; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); AZ(htc->pipeline.b); AZ(htc->pipeline.e); t = &htc->rxbuf; Tcheck(*t); assert(*t->e == '\0'); /* Skip any leading white space */ for (p = t->b ; vct_islws(*p); p++) continue; if (p == t->e) { /* All white space */ t->e = t->b; *t->e = '\0'; return (HTTP1_ALL_WHITESPACE); } while (1) { p = strchr(p, '\n'); if (p == NULL) return (HTTP1_NEED_MORE); p++; if (*p == '\r') p++; if (*p == '\n') break; } p++; WS_ReleaseP(htc->ws, t->e); if (p < t->e) { htc->pipeline.b = p; htc->pipeline.e = t->e; t->e = p; } return (HTTP1_COMPLETE); }
const char * VRT_regsub(const struct sess *sp, int all, const char *str, void *re, const char *sub) { int ovector[30]; vre_t *t; int i, l; txt res; char *b0; const char *s; unsigned u, x; AN(re); if (str == NULL) str = ""; t = re; memset(ovector, 0, sizeof(ovector)); i = VRE_exec(t, str, strlen(str), 0, 0, ovector, 30, ¶ms->vre_limits); /* If it didn't match, we can return the original string */ if (i == VRE_ERROR_NOMATCH) return(str); if (i < VRE_ERROR_NOMATCH ) { WSP(sp, SLT_VCL_Error, "Regexp matching returned %d", i); return(str); } u = WS_Reserve(sp->http->ws, 0); res.e = res.b = b0 = sp->http->ws->f; res.e += u; do { /* Copy prefix to match */ Tadd(&res, str, ovector[0]); for (s = sub ; *s != '\0'; s++ ) { if (*s != '\\' || s[1] == '\0') { if (res.b < res.e) *res.b++ = *s; continue; } s++; if (isdigit(*s)) { x = *s - '0'; l = ovector[2*x+1] - ovector[2*x]; Tadd(&res, str + ovector[2*x], l); continue; } else { if (res.b < res.e) *res.b++ = *s; } } str += ovector[1]; if (!all) break; memset(&ovector, 0, sizeof(ovector)); i = VRE_exec(t, str, strlen(str), 0, 0, ovector, 30, ¶ms->vre_limits); if (i < VRE_ERROR_NOMATCH ) { WSP(sp, SLT_VCL_Error, "Regexp matching returned %d", i); return(str); } } while (i != VRE_ERROR_NOMATCH); /* Copy suffix to match */ l = strlen(str) + 1; Tadd(&res, str, l); if (res.b >= res.e) { WS_Release(sp->http->ws, 0); return (str); } Tcheck(res); WS_ReleaseP(sp->http->ws, res.b); return (b0); }
static uint16_t htc_splitline(struct http *hp, const struct http_conn *htc, int req) { char *p; int h1, h2, h3; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); Tcheck(htc->rxbuf); if (req) { h1 = HTTP_HDR_METHOD; h2 = HTTP_HDR_URL; h3 = HTTP_HDR_PROTO; } else { h1 = HTTP_HDR_PROTO; h2 = HTTP_HDR_STATUS; h3 = HTTP_HDR_RESPONSE; } /* Skip leading LWS */ for (p = htc->rxbuf.b ; vct_islws(*p); p++) continue; hp->hd[h1].b = p; /* First field cannot contain SP or CTL */ for (; !vct_issp(*p); p++) { if (vct_isctl(*p)) return (400); } hp->hd[h1].e = p; assert(Tlen(hp->hd[h1])); /* Skip SP */ for (; vct_issp(*p); p++) { if (vct_isctl(*p)) return (400); } hp->hd[h2].b = p; /* Second field cannot contain LWS or CTL */ for (; !vct_islws(*p); p++) { if (vct_isctl(*p)) return (400); } hp->hd[h2].e = p; if (!Tlen(hp->hd[h2])) return (400); /* Skip SP */ for (; vct_issp(*p); p++) { if (vct_isctl(*p)) return (400); } hp->hd[h3].b = p; /* Third field is optional and cannot contain CTL except TAB */ for (; !vct_iscrlf(p); p++) { if (vct_isctl(*p) && !vct_issp(*p)) { hp->hd[h3].b = NULL; return (400); } } hp->hd[h3].e = p; /* Skip CRLF */ p += vct_skipcrlf(p); *hp->hd[h1].e = '\0'; *hp->hd[h2].e = '\0'; if (hp->hd[h3].e != NULL) *hp->hd[h3].e = '\0'; return (htc_dissect_hdrs(hp, p, htc)); }
const char * VRT_regsub(struct req *req, int all, const char *str, void *re, const char *sub) { int ovector[30]; vre_t *t; int i, l; txt res; char *b0; const char *s; unsigned u, x; int options = 0; size_t len; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); AN(re); if (str == NULL) str = ""; if (sub == NULL) sub = ""; t = re; memset(ovector, 0, sizeof(ovector)); len = strlen(str); i = VRE_exec(t, str, len, 0, options, ovector, 30, &cache_param->vre_limits); /* If it didn't match, we can return the original string */ if (i == VRE_ERROR_NOMATCH) return(str); if (i < VRE_ERROR_NOMATCH ) { VSLb(req->vsl, SLT_VCL_Error, "Regexp matching returned %d", i); return(str); } u = WS_Reserve(req->http->ws, 0); res.e = res.b = b0 = req->http->ws->f; res.e += u; do { /* Copy prefix to match */ Tadd(&res, str, ovector[0]); for (s = sub ; *s != '\0'; s++ ) { if (*s != '\\' || s[1] == '\0') { if (res.b < res.e) *res.b++ = *s; continue; } s++; if (isdigit(*s)) { x = *s - '0'; l = ovector[2*x+1] - ovector[2*x]; Tadd(&res, str + ovector[2*x], l); continue; } else { if (res.b < res.e) *res.b++ = *s; } } str += ovector[1]; len -= ovector[1]; if (!all) break; memset(&ovector, 0, sizeof(ovector)); options |= VRE_NOTEMPTY; i = VRE_exec(t, str, len, 0, options, ovector, 30, &cache_param->vre_limits); if (i < VRE_ERROR_NOMATCH ) { WS_Release(req->http->ws, 0); VSLb(req->vsl, SLT_VCL_Error, "Regexp matching returned %d", i); return(str); } } while (i != VRE_ERROR_NOMATCH); /* Copy suffix to match */ Tadd(&res, str, len+1); if (res.b >= res.e) { WS_Release(req->http->ws, 0); return (str); } Tcheck(res); WS_ReleaseP(req->http->ws, res.b); return (b0); }
void http_CollectHdr(struct http *hp, const char *hdr) { unsigned u, l, ml, f, x, d; char *b = NULL, *e = NULL; CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); if (WS_Overflowed(hp->ws)) return; l = hdr[0]; assert(l == strlen(hdr + 1)); assert(hdr[l] == ':'); f = http_findhdr(hp, l - 1, hdr + 1); if (f == 0) return; for (d = u = f + 1; u < hp->nhd; u++) { Tcheck(hp->hd[u]); if (!http_IsHdr(&hp->hd[u], hdr)) { if (d != u) { hp->hd[d] = hp->hd[u]; hp->hdf[d] = hp->hdf[u]; } d++; continue; } if (b == NULL) { /* Found second header, start our collection */ ml = WS_Reserve(hp->ws, 0); b = hp->ws->f; e = b + ml; x = Tlen(hp->hd[f]); if (b + x >= e) { http_fail(hp); VSLb(hp->vsl, SLT_LostHeader, "%s", hdr + 1); WS_Release(hp->ws, 0); return; } memcpy(b, hp->hd[f].b, x); b += x; } AN(b); AN(e); /* Append the Nth header we found */ if (b < e) *b++ = ','; x = Tlen(hp->hd[u]) - l; if (b + x >= e) { http_fail(hp); VSLb(hp->vsl, SLT_LostHeader, "%s", hdr + 1); WS_Release(hp->ws, 0); return; } memcpy(b, hp->hd[u].b + *hdr, x); b += x; } if (b == NULL) return; hp->nhd = (uint16_t)d; AN(e); *b = '\0'; hp->hd[f].b = hp->ws->f; hp->hd[f].e = b; WS_ReleaseP(hp->ws, b + 1); }
static uint16_t http_splitline(struct worker *w, int fd, struct http *hp, const struct http_conn *htc, int h1, int h2, int h3) { char *p, *q; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); /* XXX: Assert a NUL at rx.e ? */ Tcheck(htc->rxbuf); /* Skip leading LWS */ for (p = htc->rxbuf.b ; vct_islws(*p); p++) continue; /* First field cannot contain SP, CRLF or CTL */ q = p; for (; !vct_issp(*p); p++) { if (vct_isctl(*p)) return (400); } hp->hd[h1].b = q; hp->hd[h1].e = p; /* Skip SP */ for (; vct_issp(*p); p++) { if (vct_isctl(*p)) return (400); } /* Second field cannot contain LWS or CTL */ q = p; for (; !vct_islws(*p); p++) { if (vct_isctl(*p)) return (400); } hp->hd[h2].b = q; hp->hd[h2].e = p; if (!Tlen(hp->hd[h2])) return (413); /* Skip SP */ for (; vct_issp(*p); p++) { if (vct_isctl(*p)) return (400); } /* Third field is optional and cannot contain CTL */ q = p; if (!vct_iscrlf(*p)) { for (; !vct_iscrlf(*p); p++) if (!vct_issep(*p) && vct_isctl(*p)) return (400); } hp->hd[h3].b = q; hp->hd[h3].e = p; /* Skip CRLF */ p += vct_skipcrlf(p); *hp->hd[h1].e = '\0'; WSLH(w, fd, hp, h1); *hp->hd[h2].e = '\0'; WSLH(w, fd, hp, h2); if (hp->hd[h3].e != NULL) { *hp->hd[h3].e = '\0'; WSLH(w, fd, hp, h3); } return (http_dissect_hdrs(w, hp, fd, p, htc)); }