void http_CopyHome(const struct http *hp) { unsigned u, l; char *p; for (u = 0; u < hp->nhd; u++) { if (hp->hd[u].b == NULL) continue; if (hp->hd[u].b >= hp->ws->s && hp->hd[u].e <= hp->ws->e) { http_VSLH(hp, u); continue; } l = Tlen(hp->hd[u]); p = WS_Copy(hp->ws, hp->hd[u].b, l + 1L); if (p != NULL) { http_VSLH(hp, u); hp->hd[u].b = p; hp->hd[u].e = p + l; } else { /* XXX This leaves a slot empty */ VSC_C_main->losthdr++; VSLbt(hp->vsl, SLT_LostHeader, hp->hd[u]); hp->hd[u].b = NULL; hp->hd[u].e = NULL; } } }
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_VSL_log(const struct http *hp) { unsigned u; for (u = 0; u < hp->nhd; u++) if (hp->hd[u].b != NULL) http_VSLH(hp, u); }
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]; http_VSLH(to, n); }
void http_SetH(const struct http *to, unsigned n, const char *fm) { assert(n < to->shd); AN(fm); to->hd[n].b = TRUST_ME(fm); to->hd[n].e = strchr(to->hd[n].b, '\0'); to->hdf[n] = 0; http_VSLH(to, n); }
static void http_PutField(const struct http *to, int field, const char *string) { char *p; CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); p = WS_Copy(to->ws, string, -1); if (p == NULL) { http_fail(to); VSLb(to->vsl, SLT_LostHeader, "%s", string); return; } to->hd[field].b = p; to->hd[field].e = strchr(p, '\0'); to->hdf[field] = 0; http_VSLH(to, field); }
unsigned http_Write(const struct worker *w, const struct http *hp, int resp) { unsigned u, l; if (resp) { l = WRW_WriteH(w, &hp->hd[HTTP_HDR_PROTO], " "); http_VSLH(hp, HTTP_HDR_PROTO); hp->hd[HTTP_HDR_STATUS].b = WS_Alloc(hp->ws, 4); AN(hp->hd[HTTP_HDR_STATUS].b); sprintf(hp->hd[HTTP_HDR_STATUS].b, "%3d", hp->status); hp->hd[HTTP_HDR_STATUS].e = hp->hd[HTTP_HDR_STATUS].b + 3; l += WRW_WriteH(w, &hp->hd[HTTP_HDR_STATUS], " "); http_VSLH(hp, HTTP_HDR_STATUS); l += WRW_WriteH(w, &hp->hd[HTTP_HDR_RESPONSE], "\r\n"); http_VSLH(hp, HTTP_HDR_RESPONSE); } else { AN(hp->hd[HTTP_HDR_URL].b); l = WRW_WriteH(w, &hp->hd[HTTP_HDR_REQ], " "); http_VSLH(hp, HTTP_HDR_REQ); l += WRW_WriteH(w, &hp->hd[HTTP_HDR_URL], " "); http_VSLH(hp, HTTP_HDR_URL); l += WRW_WriteH(w, &hp->hd[HTTP_HDR_PROTO], "\r\n"); http_VSLH(hp, HTTP_HDR_PROTO); } for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) { if (hp->hd[u].b == NULL) continue; AN(hp->hd[u].b); AN(hp->hd[u].e); l += WRW_WriteH(w, &hp->hd[u], "\r\n"); http_VSLH(hp, u); } l += WRW_Write(w, "\r\n", -1); return (l); }
void http_PrintfHeader(struct http *to, const char *fmt, ...) { va_list ap; unsigned l, n; CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); l = WS_Reserve(to->ws, 0); va_start(ap, fmt); n = vsnprintf(to->ws->f, l, fmt, ap); va_end(ap); if (n + 1 >= l || to->nhd >= to->shd) { http_fail(to); VSLb(to->vsl, SLT_LostHeader, "%s", to->ws->f); WS_Release(to->ws, 0); return; } to->hd[to->nhd].b = to->ws->f; to->hd[to->nhd].e = to->ws->f + n; to->hdf[to->nhd] = 0; WS_Release(to->ws, n + 1); http_VSLH(to, to->nhd); to->nhd++; }
static uint16_t http_splitline(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'; http_VSLH(hp, h1); *hp->hd[h2].e = '\0'; http_VSLH(hp, h2); if (hp->hd[h3].e != NULL) { *hp->hd[h3].e = '\0'; http_VSLH(hp, h3); } return (http_dissect_hdrs(hp, p, htc)); }
static uint16_t http_dissect_hdrs(struct http *hp, char *p, const struct http_conn *htc) { char *q, *r; txt t = htc->rxbuf; if (*p == '\r') p++; hp->nhd = HTTP_HDR_FIRST; hp->conds = 0; r = NULL; /* For FlexeLint */ for (; p < t.e; p = r) { /* Find end of next header */ q = r = p; while (r < t.e) { if (!vct_iscrlf(*r)) { r++; continue; } q = r; assert(r < t.e); r += vct_skipcrlf(r); if (r >= t.e) break; /* If line does not continue: got it. */ if (!vct_issp(*r)) break; /* Clear line continuation LWS to spaces */ while (vct_islws(*q)) *q++ = ' '; } if (q - p > htc->maxhdr) { VSC_C_main->losthdr++; VSLb(hp->vsl, SLT_LostHeader, "%.*s", (int)(q - p > 20 ? 20 : q - p), p); return (413); } /* Empty header = end of headers */ if (p == q) break; if ((p[0] == 'i' || p[0] == 'I') && (p[1] == 'f' || p[1] == 'F') && p[2] == '-') hp->conds = 1; while (q > p && vct_issp(q[-1])) q--; *q = '\0'; if (hp->nhd < hp->shd) { hp->hdf[hp->nhd] = 0; hp->hd[hp->nhd].b = p; hp->hd[hp->nhd].e = q; http_VSLH(hp, hp->nhd); hp->nhd++; } else { VSC_C_main->losthdr++; VSLb(hp->vsl, SLT_LostHeader, "%.*s", (int)(q - p > 20 ? 20 : q - p), p); return (413); } } return (0); }