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); }
uint16_t HTTP1_DissectResponse(struct http_conn *htc, struct http *hp, const struct http *req) { uint16_t retval = 0; const char *p; int8_t rv; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); CHECK_OBJ_NOTNULL(req, HTTP_MAGIC); if (http1_splitline(hp, htc, HTTP1_Resp, cache_param->http_resp_hdr_len)) retval = 503; if (retval == 0) { hp->protover = http1_proto_ver(hp); if (hp->protover == 0) retval = 503; rv = http1_proto_ver(req); if (hp->protover > rv) hp->protover = rv; } if (retval == 0 && Tlen(hp->hd[HTTP_HDR_STATUS]) != 3) retval = 503; if (retval == 0) { p = hp->hd[HTTP_HDR_STATUS].b; if (p[0] >= '1' && p[0] <= '9' && p[1] >= '0' && p[1] <= '9' && p[2] >= '0' && p[2] <= '9') hp->status = 100 * (p[0] - '0') + 10 * (p[1] - '0') + p[2] - '0'; else retval = 503; } if (retval != 0) { VSLb(hp->vsl, SLT_HttpGarbage, "%.*s", (int)(htc->rxbuf_e - htc->rxbuf_b), htc->rxbuf_b); assert(retval >= 100 && retval <= 999); assert(retval == 503); hp->status = retval; http_SetH(hp, HTTP_HDR_STATUS, "503"); http_SetH(hp, HTTP_HDR_REASON, http_Status2Reason(retval)); } if (hp->hd[HTTP_HDR_REASON].b == NULL || !Tlen(hp->hd[HTTP_HDR_REASON])) http_SetH(hp, HTTP_HDR_REASON, http_Status2Reason(hp->status)); htc->body_status = http1_body_status(hp, htc, 0); return (retval); }
uint16_t http_DissectResponse(struct worker *w, const struct http_conn *htc, struct http *hp) { int j; uint16_t retval = 0; char *p; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); hp->logtag = HTTP_Rx; if (http_splitline(w, htc->fd, hp, htc, HTTP_HDR_PROTO, HTTP_HDR_STATUS, HTTP_HDR_RESPONSE)) retval = 503; if (retval == 0 && memcmp(hp->hd[HTTP_HDR_PROTO].b, "HTTP/1.", 7)) retval = 503; if (retval == 0 && Tlen(hp->hd[HTTP_HDR_STATUS]) != 3) retval = 503; if (retval == 0) { hp->status = 0; p = hp->hd[HTTP_HDR_STATUS].b; for (j = 100; j != 0; j /= 10) { if (!vct_isdigit(*p)) { retval = 503; break; } hp->status += (uint16_t)(j * (*p - '0')); p++; } if (*p != '\0') retval = 503; } if (retval != 0) { WSLR(w, SLT_HttpGarbage, htc->fd, htc->rxbuf); assert(retval >= 100 && retval <= 999); hp->status = retval; } else { http_ProtoVer(hp); } if (hp->hd[HTTP_HDR_RESPONSE].b == NULL || !Tlen(hp->hd[HTTP_HDR_RESPONSE])) { /* Backend didn't send a response string, use the standard */ hp->hd[HTTP_HDR_RESPONSE].b = TRUST_ME(http_StatusMessage(hp->status)); hp->hd[HTTP_HDR_RESPONSE].e = strchr(hp->hd[HTTP_HDR_RESPONSE].b, '\0'); } return (retval); }
uint16_t HTTP1_DissectResponse(struct http *hp, const struct http_conn *htc) { uint16_t retval = 0; char *p; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); if (htc_splitline(hp, htc, 0)) retval = 503; if (retval == 0 && memcmp(hp->hd[HTTP_HDR_PROTO].b, "HTTP/1.", 7)) retval = 503; if (retval == 0 && Tlen(hp->hd[HTTP_HDR_STATUS]) != 3) retval = 503; if (retval == 0) { p = hp->hd[HTTP_HDR_STATUS].b; if (p[0] >= '1' && p[0] <= '9' && p[1] >= '0' && p[1] <= '9' && p[2] >= '0' && p[2] <= '9') hp->status = 100 * (p[0] - '0') + 10 * (p[1] - '0') + p[2] - '0'; else retval = 503; } if (retval != 0) { VSLbt(hp->vsl, SLT_HttpGarbage, htc->rxbuf); assert(retval >= 100 && retval <= 999); hp->status = retval; } else htc_proto_ver(hp); if (hp->hd[HTTP_HDR_RESPONSE].b == NULL || !Tlen(hp->hd[HTTP_HDR_RESPONSE])) { /* Backend didn't send a response string, use the standard */ hp->hd[HTTP_HDR_RESPONSE].b = TRUST_ME(http_StatusMessage(hp->status)); hp->hd[HTTP_HDR_RESPONSE].e = strchr(hp->hd[HTTP_HDR_RESPONSE].b, '\0'); } return (retval); }
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); }
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); }
void http_CopyHome(struct worker *w, int fd, 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) { WSLH(w, fd, hp, u); continue; } l = Tlen(hp->hd[u]); p = WS_Alloc(hp->ws, l + 1); if (p != NULL) { WSLH(w, fd, hp, u); memcpy(p, hp->hd[u].b, l + 1L); hp->hd[u].b = p; hp->hd[u].e = p + l; } else { /* XXX This leaves a slot empty */ VSC_C_main->losthdr++; WSLR(w, SLT_LostHeader, fd, hp->hd[u]); hp->hd[u].b = NULL; hp->hd[u].e = NULL; } } }
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; } } }
ssize_t HTTP1_Read(struct http_conn *htc, void *d, size_t len) { size_t l; unsigned char *p; ssize_t i; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); l = 0; p = d; if (htc->pipeline.b) { l = Tlen(htc->pipeline); if (l > len) l = len; memcpy(p, htc->pipeline.b, l); p += l; len -= l; htc->pipeline.b += l; if (htc->pipeline.b == htc->pipeline.e) htc->pipeline.b = htc->pipeline.e = NULL; } if (len == 0) return (l); i = read(htc->fd, p, len); if (i < 0) { VSLb(htc->vsl, SLT_FetchError, "%s", strerror(errno)); return (i); } return (i + l); }
static int cnt_wait(struct sess *sp) { int i; struct pollfd pfd[1]; struct worker *wrk; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); wrk = sp->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); AZ(sp->vcl); AZ(wrk->obj); AZ(sp->esi_level); assert(sp->xid == 0); i = HTC_Complete(sp->htc); if (i == 0 && cache_param->session_linger > 0) { pfd[0].fd = sp->fd; pfd[0].events = POLLIN; pfd[0].revents = 0; i = poll(pfd, 1, cache_param->session_linger); if (i) i = HTC_Rx(sp->htc); } if (i == 0) { WSP(sp, SLT_Debug, "herding"); wrk->stats.sess_herd++; SES_Charge(sp); Pool_Wait(sp); return (1); } if (i == 1) { sp->step = STP_START; return (0); } if (i == -2) { SES_Close(sp, "overflow"); } else if (i == -1 && Tlen(sp->htc->rxbuf) == 0 && (errno == 0 || errno == ECONNRESET)) SES_Close(sp, "EOF"); else SES_Close(sp, "error"); sp->step = STP_DONE; return (0); }
int HTC_Reinit(struct http_conn *htc) { unsigned l; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); (void)WS_Reserve(htc->ws, (htc->ws->e - htc->ws->s) / 2); htc->rxbuf.b = htc->ws->f; htc->rxbuf.e = htc->ws->f; if (htc->pipeline.b != NULL) { l = Tlen(htc->pipeline); memmove(htc->rxbuf.b, htc->pipeline.b, l); htc->rxbuf.e += l; htc->pipeline.b = NULL; htc->pipeline.e = NULL; } *htc->rxbuf.e = '\0'; return (HTC_Complete(htc)); }
static int cnt_wait(struct sess *sp) { int i; struct pollfd pfd[1]; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); AZ(sp->vcl); AZ(sp->obj); assert(sp->xid == 0); i = HTC_Complete(sp->htc); while (i == 0) { if (params->session_linger > 0) { pfd[0].fd = sp->fd; pfd[0].events = POLLIN; pfd[0].revents = 0; i = poll(pfd, 1, params->session_linger); if (i == 0) { WSL(sp->wrk, SLT_Debug, sp->fd, "herding"); VSL_stats->sess_herd++; sp->wrk = NULL; vca_return_session(sp); return (1); } } i = HTC_Rx(sp->htc); } if (i == 1) { sp->step = STP_START; } else { if (i == -2) vca_close_session(sp, "overflow"); else if (i == -1 && Tlen(sp->htc->rxbuf) == 0 && (errno == 0 || errno == ECONNRESET)) vca_close_session(sp, "EOF"); else vca_close_session(sp, "error"); sp->step = STP_DONE; } return (0); }
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) continue; l = Tlen(hp->hd[u]); p = WS_Copy(hp->ws, hp->hd[u].b, l + 1L); if (p == NULL) { http_fail(hp); VSLb(hp->vsl, SLT_LostHeader, "%s", hp->hd[u].b); return; } hp->hd[u].b = p; hp->hd[u].e = p + l; } }
int HTC_Read(struct http_conn *htc, void *d, unsigned len) { unsigned l; unsigned char *p; int i; assert(len > 0); l = 0; p = d; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); if (htc->pipeline.b) { l = Tlen(htc->pipeline); if (l > len) l = len; memcpy(p, htc->pipeline.b, l); p += l; len -= l; htc->pipeline.b += l; if (htc->pipeline.b == htc->pipeline.e) htc->pipeline.b = htc->pipeline.e = NULL; if (l > 0) return (l); } if (len == 0) return (l); i = CFD_read(&htc->fds, p, len); if (i == -2) { if (l > 0) return (l); return (-2); } if (i < 0) return (i); return (i + l); }
unsigned http_EstimateWS(const struct http *fm, unsigned how, uint16_t *nhd) { unsigned u, l; l = 0; *nhd = HTTP_HDR_FIRST; CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC); for (u = 0; 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 l += PRNDUP(Tlen(fm->hd[u]) + 1); (*nhd)++; // fm->hdf[u] |= HDF_COPY; } return (l); }
static uint16_t http1_dissect_hdrs(struct http *hp, char *p, struct http_conn *htc, unsigned maxhdr) { char *q, *r; assert(p > htc->rxbuf_b); assert(p <= htc->rxbuf_e); hp->nhd = HTTP_HDR_FIRST; hp->conds = 0; r = NULL; /* For FlexeLint */ for (; p < htc->rxbuf_e; p = r) { /* Find end of next header */ q = r = p; if (vct_iscrlf(p)) break; while (r < htc->rxbuf_e) { if (!vct_isctl(*r) || vct_issp(*r)) { r++; continue; } if (!vct_iscrlf(r)) { VSLb(hp->vsl, SLT_BogoHeader, "Header has ctrl char 0x%02x", *r); return (400); } q = r; assert(r < htc->rxbuf_e); r += vct_skipcrlf(r); if (r >= htc->rxbuf_e) break; if (vct_iscrlf(r)) 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 > maxhdr) { VSLb(hp->vsl, SLT_BogoHeader, "Header too long: %.*s", (int)(q - p > 20 ? 20 : q - p), p); return (400); } /* Empty header = end of headers */ if (p == q) break; if (vct_islws(*p)) { VSLb(hp->vsl, SLT_BogoHeader, "1st header has white space: %.*s", (int)(q - p > 20 ? 20 : q - p), p); return (400); } 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 (strchr(p, ':') == NULL) { VSLb(hp->vsl, SLT_BogoHeader, "Header without ':' %.*s", (int)(q - p > 20 ? 20 : q - p), p); return (400); } if (hp->nhd < hp->shd) { hp->hdf[hp->nhd] = 0; hp->hd[hp->nhd].b = p; hp->hd[hp->nhd].e = q; hp->nhd++; } else { VSLb(hp->vsl, SLT_BogoHeader, "Too many headers: %.*s", (int)(q - p > 20 ? 20 : q - p), p); return (400); } for (; p < q; p++) { if (vct_islws(*p)) { VSLb(hp->vsl, SLT_BogoHeader, "Space in header '%.*s'", (int)Tlen(hp->hd[hp->nhd - 1]), hp->hd[hp->nhd - 1].b); return (400); } if (*p == ':') break; } } if (p < htc->rxbuf_e) p += vct_skipcrlf(p); HTC_RxPipeline(htc, p); htc->rxbuf_e = p; return (0); }
void PipeRequest(struct req *req) { struct vbc *vc; struct worker *wrk; struct pollfd fds[2]; struct busyobj *bo; int i; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->sp, SESS_MAGIC); wrk = req->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); bo = req->busyobj; CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); vc = VDI_GetFd(NULL, bo); if (vc == NULL) return; bo->vbc = vc; /* For panic dumping */ (void)VTCP_blocking(vc->fd); WRW_Reserve(wrk, &vc->fd, bo->vsl, req->t_req); req->acct_req.hdrbytes += HTTP1_Write(wrk, bo->bereq, 0); if (req->htc->pipeline.b != NULL) req->acct_req.bodybytes += WRW_Write(wrk, req->htc->pipeline.b, Tlen(req->htc->pipeline)); i = WRW_FlushRelease(wrk); if (i) { SES_Close(req->sp, SC_TX_PIPE); VDI_CloseFd(&vc); return; } req->t_resp = VTIM_real(); memset(fds, 0, sizeof fds); // XXX: not yet (void)VTCP_linger(vc->fd, 0); fds[0].fd = vc->fd; fds[0].events = POLLIN | POLLERR; // XXX: not yet (void)VTCP_linger(req->sp->fd, 0); fds[1].fd = req->sp->fd; fds[1].events = POLLIN | POLLERR; while (fds[0].fd > -1 || fds[1].fd > -1) { fds[0].revents = 0; fds[1].revents = 0; i = poll(fds, 2, cache_param->pipe_timeout * 1000); if (i < 1) break; if (fds[0].revents && rdf(vc->fd, req->sp->fd)) { if (fds[1].fd == -1) break; (void)shutdown(vc->fd, SHUT_RD); (void)shutdown(req->sp->fd, SHUT_WR); fds[0].events = 0; fds[0].fd = -1; } if (fds[1].revents && rdf(req->sp->fd, vc->fd)) { if (fds[0].fd == -1) break; (void)shutdown(req->sp->fd, SHUT_RD); (void)shutdown(vc->fd, SHUT_WR); fds[1].events = 0; fds[1].fd = -1; } } SES_Close(req->sp, SC_TX_PIPE); VDI_CloseFd(&vc); bo->vbc = NULL; }
static int cnt_done(struct sess *sp) { double dh, dp, da; int i; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); CHECK_OBJ_ORNULL(sp->vcl, VCL_CONF_MAGIC); AZ(sp->obj); AZ(sp->vbe); sp->director = NULL; sp->restarts = 0; if (sp->vcl != NULL && sp->esis == 0) { if (sp->wrk->vcl != NULL) VCL_Rel(&sp->wrk->vcl); sp->wrk->vcl = sp->vcl; sp->vcl = NULL; } sp->t_end = TIM_real(); sp->wrk->lastused = sp->t_end; if (sp->xid == 0) { sp->t_req = sp->t_end; sp->t_resp = sp->t_end; } dp = sp->t_resp - sp->t_req; da = sp->t_end - sp->t_resp; dh = sp->t_req - sp->t_open; WSL(sp->wrk, SLT_ReqEnd, sp->id, "%u %.9f %.9f %.9f %.9f %.9f", sp->xid, sp->t_req, sp->t_end, dh, dp, da); sp->xid = 0; sp->t_open = sp->t_end; sp->t_resp = NAN; WSL_Flush(sp->wrk, 0); /* If we did an ESI include, don't mess up our state */ if (sp->esis > 0) return (1); sp->t_req = NAN; if (sp->fd >= 0 && sp->doclose != NULL) { /* * This is an orderly close of the connection; ditch nolinger * before we close, to get queued data transmitted. */ TCP_linger(sp->fd, 0); vca_close_session(sp, sp->doclose); } if (sp->fd < 0) { SES_Charge(sp); VSL_stats->sess_closed++; sp->wrk = NULL; SES_Delete(sp); return (1); } /* Reset the workspace to the session-watermark */ WS_Reset(sp->ws, sp->ws_ses); i = HTC_Reinit(sp->htc); if (i == 1) { VSL_stats->sess_pipeline++; sp->step = STP_START; return (0); } if (Tlen(sp->htc->rxbuf)) { VSL_stats->sess_readahead++; sp->step = STP_WAIT; return (0); } if (params->session_linger > 0) { VSL_stats->sess_linger++; sp->step = STP_WAIT; return (0); } VSL_stats->sess_herd++; SES_Charge(sp); sp->wrk = NULL; vca_return_session(sp); return (1); }
void PipeSession(struct sess *sp) { struct vbc *vc; struct worker *w; struct pollfd fds[2]; int i; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC); w = sp->wrk; sp->vbc = VDI_GetFd(NULL, sp); if (sp->vbc == NULL) return; vc = sp->vbc; (void)VTCP_blocking(vc->fd); WRW_Reserve(w, &vc->fd); sp->wrk->acct_tmp.hdrbytes += http_Write(w, sp->vsl_id, sp->wrk->bereq, 0); if (sp->htc->pipeline.b != NULL) sp->wrk->acct_tmp.bodybytes += WRW_Write(w, sp->htc->pipeline.b, Tlen(sp->htc->pipeline)); i = WRW_FlushRelease(w); if (i) { SES_Close(sp, "pipe"); VDI_CloseFd(sp); return; } sp->t_resp = VTIM_real(); memset(fds, 0, sizeof fds); // XXX: not yet (void)VTCP_linger(vc->fd, 0); fds[0].fd = vc->fd; fds[0].events = POLLIN | POLLERR; // XXX: not yet (void)VTCP_linger(sp->fd, 0); fds[1].fd = sp->fd; fds[1].events = POLLIN | POLLERR; while (fds[0].fd > -1 || fds[1].fd > -1) { fds[0].revents = 0; fds[1].revents = 0; i = poll(fds, 2, params->pipe_timeout * 1000); if (i < 1) break; if (fds[0].revents && rdf(vc->fd, sp->fd)) { if (fds[1].fd == -1) break; (void)shutdown(vc->fd, SHUT_RD); (void)shutdown(sp->fd, SHUT_WR); fds[0].events = 0; fds[0].fd = -1; } if (fds[1].revents && rdf(sp->fd, vc->fd)) { if (fds[0].fd == -1) break; (void)shutdown(sp->fd, SHUT_RD); (void)shutdown(vc->fd, SHUT_WR); fds[1].events = 0; fds[1].fd = -1; } } SES_Close(sp, "pipe"); VDI_CloseFd(sp); }
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)); }
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 int cnt_done(struct sess *sp) { double dh, dp, da; int i; struct worker *wrk; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); wrk = sp->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_ORNULL(sp->vcl, VCL_CONF_MAGIC); AZ(wrk->obj); AZ(wrk->busyobj); sp->director = NULL; sp->restarts = 0; wrk->busyobj = NULL; SES_Charge(sp); /* If we did an ESI include, don't mess up our state */ if (sp->esi_level > 0) return (1); if (sp->vcl != NULL) { if (wrk->vcl != NULL) VCL_Rel(&wrk->vcl); wrk->vcl = sp->vcl; sp->vcl = NULL; } sp->t_end = W_TIM_real(wrk); WSP(sp, SLT_Debug, "PHK req %.9f resp %.9f end %.9f open %.9f", sp->t_req, sp->t_resp, sp->t_end, sp->t_open); if (sp->xid == 0) { // sp->t_req = sp->t_end; sp->t_resp = sp->t_end; } else { dp = sp->t_resp - sp->t_req; da = sp->t_end - sp->t_resp; dh = sp->t_req - sp->t_open; /* XXX: Add StatReq == StatSess */ /* XXX: Workaround for pipe */ if (sp->fd >= 0) { WSP(sp, SLT_Length, "%ju", (uintmax_t)sp->req_bodybytes); } WSP(sp, SLT_ReqEnd, "%u %.9f %.9f %.9f %.9f %.9f", sp->xid, sp->t_req, sp->t_end, dh, dp, da); } sp->xid = 0; WSL_Flush(wrk, 0); sp->t_open = sp->t_end; sp->t_resp = NAN; sp->req_bodybytes = 0; sp->t_req = NAN; sp->hash_always_miss = 0; sp->hash_ignore_busy = 0; if (sp->fd >= 0 && sp->doclose != NULL) { /* * This is an orderly close of the connection; ditch nolinger * before we close, to get queued data transmitted. */ // XXX: not yet (void)VTCP_linger(sp->fd, 0); SES_Close(sp, sp->doclose); } if (sp->fd < 0) { wrk->stats.sess_closed++; SES_Delete(sp, NULL); return (1); } if (wrk->stats.client_req >= cache_param->wthread_stats_rate) WRK_SumStat(wrk); /* Reset the workspace to the session-watermark */ WS_Reset(sp->ws, sp->ws_ses); WS_Reset(wrk->ws, NULL); i = HTC_Reinit(sp->htc); if (i == 1) { wrk->stats.sess_pipeline++; sp->step = STP_START; return (0); } if (Tlen(sp->htc->rxbuf)) { wrk->stats.sess_readahead++; sp->step = STP_WAIT; return (0); } if (cache_param->session_linger > 0) { wrk->stats.sess_linger++; sp->step = STP_WAIT; return (0); } wrk->stats.sess_herd++; Pool_Wait(sp); return (1); }
static enum req_fsm_nxt http1_wait(struct sess *sp, struct worker *wrk, struct req *req) { int j, tmo; struct pollfd pfd[1]; double now, when; enum sess_close why = SC_NULL; enum http1_status_e hs; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); assert(req->sp == sp); AZ(req->vcl); AZ(req->esi_level); AZ(isnan(sp->t_idle)); assert(isnan(req->t_first)); assert(isnan(req->t_prev)); assert(isnan(req->t_req)); tmo = (int)(1e3 * cache_param->timeout_linger); while (1) { pfd[0].fd = sp->fd; pfd[0].events = POLLIN; pfd[0].revents = 0; j = poll(pfd, 1, tmo); assert(j >= 0); now = VTIM_real(); if (j != 0) hs = HTTP1_Rx(req->htc); else hs = HTTP1_Complete(req->htc); if (hs == HTTP1_COMPLETE) { /* Got it, run with it */ if (isnan(req->t_first)) req->t_first = now; if (isnan(req->t_req)) req->t_req = now; req->acct.req_hdrbytes += Tlen(req->htc->rxbuf); return (REQ_FSM_MORE); } else if (hs == HTTP1_ERROR_EOF) { why = SC_REM_CLOSE; break; } else if (hs == HTTP1_OVERFLOW) { why = SC_RX_OVERFLOW; break; } else if (hs == HTTP1_ALL_WHITESPACE) { /* Nothing but whitespace */ when = sp->t_idle + cache_param->timeout_idle; if (when < now) { why = SC_RX_TIMEOUT; break; } when = sp->t_idle + cache_param->timeout_linger; tmo = (int)(1e3 * (when - now)); if (when < now || tmo == 0) { wrk->stats->sess_herd++; SES_ReleaseReq(req); WAIT_Enter(sp); return (REQ_FSM_DONE); } } else { /* Working on it */ if (isnan(req->t_first)) /* Record first byte received time stamp */ req->t_first = now; when = sp->t_idle + cache_param->timeout_req; tmo = (int)(1e3 * (when - now)); if (when < now || tmo == 0) { why = SC_RX_TIMEOUT; break; } } } req->acct.req_hdrbytes += Tlen(req->htc->rxbuf); CNT_AcctLogCharge(wrk->stats, req); SES_ReleaseReq(req); assert(why != SC_NULL); SES_Delete(sp, why, now); return (REQ_FSM_DONE); }
static uint16_t http1_splitline(struct http *hp, struct http_conn *htc, const int *hf, unsigned maxhdr) { char *p; int i; assert(hf == HTTP1_Req || hf == HTTP1_Resp); CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); assert(htc->rxbuf_e >= htc->rxbuf_b); AZ(hp->hd[hf[0]].b); AZ(hp->hd[hf[1]].b); AZ(hp->hd[hf[2]].b); /* Skip leading LWS */ for (p = htc->rxbuf_b ; vct_islws(*p); p++) continue; hp->hd[hf[0]].b = p; /* First field cannot contain SP or CTL */ for (; !vct_issp(*p); p++) { if (vct_isctl(*p)) return (400); } hp->hd[hf[0]].e = p; assert(Tlen(hp->hd[hf[0]])); *p++ = '\0'; /* Skip SP */ for (; vct_issp(*p); p++) { if (vct_isctl(*p)) return (400); } hp->hd[hf[1]].b = p; /* Second field cannot contain LWS or CTL */ for (; !vct_islws(*p); p++) { if (vct_isctl(*p)) return (400); } hp->hd[hf[1]].e = p; if (!Tlen(hp->hd[hf[1]])) return (400); *p++ = '\0'; /* Skip SP */ for (; vct_issp(*p); p++) { if (vct_isctl(*p)) return (400); } hp->hd[hf[2]].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[hf[2]].b = NULL; return (400); } } hp->hd[hf[2]].e = p; /* Skip CRLF */ i = vct_skipcrlf(p); *p = '\0'; p += i; return (http1_dissect_hdrs(hp, p, htc, maxhdr)); }
int vmod_parse(struct sess *sp,const char* tgHeadName,unsigned setParam,const char* paramPrefix,unsigned parseMulti,unsigned parseFile){ #ifdef DEBUG_SYSLOG syslog(6,"parse:start"); #endif /* struct sess *sp, OK const char* tgHeadName, OK const char* paramPrefix, url, unsigned setParam, url, unsigned parseMulti, OK unsigned parseFile OK */ //デバッグでReInitとかrestartの時に不具合でないかチェック(ロールバックも) //Content = pipeline.e-bの時はRxbuf確保をしない(必要ないので) //mix形式をurlencodeに切り替える(組み換えで安全に)<-完了 /* string(41) "submitter\"=a&submitter2=b&submitter3=vcc" string(42) "submitter%5C=a&submitter2=b&submitter3=vcc" string(39) "submitter=a&submitter2=b&submitter3=vcc" string(39) "submitter=a&submitter2=b&submitter3=vcc" string(83) "submitter=%e3%81%82%e3%81%84%e3%81%86%e3%81%88%e3%81%8a&submitter2=b&submitter3=vcc" string(83) "submitter=%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A&submitter2=b&submitter3=vcc" 1 =成功 -1 =エラー ワークスペースサイズが足りない -2 =エラー target/ContentLengthがない/不正 -3 =エラー 指定ContentLengthに満たないデータ -4 =エラー 未対応形式 if (!( !VRT_strcmp(VRT_r_req_request(sp), "POST") || !VRT_strcmp(VRT_r_req_request(sp), "PUT") )){return "";} */ unsigned long content_length,orig_content_length; char *h_clen_ptr, *h_ctype_ptr, *body; int buf_size, rsize; char buf[1024],tgHead[256]; unsigned multipart = 0; ////////////////////////////// //build tgHead int hsize = strlen(tgHeadName) +1; if(hsize > 1){ if(hsize > 255){ #ifdef DEBUG_SYSLOG syslog(6,"parse:err -2"); #endif return -2; } tgHead[0] = hsize; tgHead[1] = 0; snprintf(tgHead +1,255,"%s:",tgHeadName); }else{ tgHead[0] = 0; } ////////////////////////////// //check Content-Type #ifdef DEBUG_SYSLOG syslog(6,"GetHdr Content-Type:"); #endif h_ctype_ptr = VRT_GetHdr(sp, HDR_REQ, "\015Content-Type:"); if(h_ctype_ptr != NULL){ if (h_ctype_ptr == strstr(h_ctype_ptr, "application/x-www-form-urlencoded")) { //application/x-www-form-urlencoded }else if(h_ctype_ptr == strstr(h_ctype_ptr, "multipart/form-data") && parseMulti){ //multipart/form-data multipart = 1; }else{ #ifdef DEBUG_SYSLOG syslog(6,"parse:err -4"); #endif return -4; } }else{ //none support type #ifdef DEBUG_SYSLOG syslog(6,"parse:err -4"); #endif return -4; } ////////////////////////////// //check Content-Length #ifdef DEBUG_SYSLOG syslog(6,"GetHdr Content-Length:"); #endif h_clen_ptr = VRT_GetHdr(sp, HDR_REQ, "\017Content-Length:"); if (!h_clen_ptr) { //can't get #ifdef DEBUG_SYSLOG syslog(6,"parse:err -2"); #endif return -2; } orig_content_length = content_length = strtoul(h_clen_ptr, NULL, 10); if (content_length <= 0) { //illegal length #ifdef DEBUG_SYSLOG syslog(6,"parse:err -2"); #endif return -2; } ////////////////////////////// //Check POST data is loaded #ifdef DEBUG_HTCREAD if(0 == 1){ #else if(sp->htc->pipeline.b != NULL && Tlen(sp->htc->pipeline) == content_length){ #endif #ifdef DEBUG_SYSLOG syslog(6,"noread"); #endif //complete read body = sp->htc->pipeline.b; }else{ #ifdef DEBUG_SYSLOG syslog(6,"read"); #endif //incomplete read int rxbuf_size = Tlen(sp->htc->rxbuf); /////////////////////////////////////////////// //use ws int u = WS_Reserve(sp->wrk->ws, 0); if(u < content_length + rxbuf_size + 1){ #ifdef DEBUG_SYSLOG syslog(6,"parse:err -1"); #endif return -1; } body = (char*)sp->wrk->ws->f; memcpy(body, sp->htc->rxbuf.b, rxbuf_size); sp->htc->rxbuf.b = body; body += rxbuf_size; body[0]= 0; sp->htc->rxbuf.e = body; WS_Release(sp->wrk->ws,content_length + rxbuf_size + 1); /////////////////////////////////////////////// ////////////////////////////// //read post data while (content_length) { if (content_length > sizeof(buf)) { buf_size = sizeof(buf) - 1; } else { buf_size = content_length; } // read body data into 'buf' //rsize = HTC_Read(sp->htc, buf, buf_size); rsize = vmod_HTC_Read(sp->wrk, sp->htc, buf, buf_size); if (rsize <= 0) { #ifdef DEBUG_SYSLOG syslog(6,"parse:err -3"); #endif return -3; } hsize += rsize; content_length -= rsize; strncat(body, buf, buf_size); } sp->htc->pipeline.b = body; sp->htc->pipeline.e = body + orig_content_length; } ////////////////////////////// //decode form #ifdef DEBUG_SYSLOG syslog(6,"content-size (orig)%d (read)%d",orig_content_length,strlen(body)); #endif int ret = 1; if(multipart){ ret = decodeForm_multipart(sp, body,tgHead,parseFile,paramPrefix,setParam); }else{ if(tgHead[0] != 0) VRT_SetHdr(sp, HDR_REQ, tgHead, body, vrt_magic_string_end); if(setParam) ret = decodeForm_urlencoded(sp, body,paramPrefix); } #ifdef DEBUG_SYSLOG syslog(6,"parse:end %d",ret); #endif return ret; }
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)); }
static enum http1_cleanup_ret http1_cleanup(struct sess *sp, struct worker *wrk, struct req *req) { CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_ORNULL(req->vcl, VCL_CONF_MAGIC); req->director_hint = NULL; req->restarts = 0; AZ(req->esi_level); if (req->vcl != NULL) { if (wrk->vcl != NULL) VCL_Rel(&wrk->vcl); wrk->vcl = req->vcl; req->vcl = NULL; } /* Charge and log byte counters */ AN(req->vsl->wid); CNT_AcctLogCharge(wrk->stats, req); req->req_bodybytes = 0; req->resp_hdrbytes = 0; req->resp_bodybytes = 0; VSL_End(req->vsl); if (!isnan(req->t_prev) && req->t_prev > 0.) sp->t_idle = req->t_prev; else sp->t_idle = W_TIM_real(wrk); req->t_first = NAN; req->t_prev = NAN; req->t_req = NAN; req->req_body_status = REQ_BODY_INIT; req->hash_always_miss = 0; req->hash_ignore_busy = 0; if (sp->fd >= 0 && req->doclose != SC_NULL) SES_Close(sp, req->doclose); if (sp->fd < 0) { wrk->stats->sess_closed++; AZ(req->vcl); SES_ReleaseReq(req); SES_Delete(sp, SC_NULL, NAN); return (SESS_DONE_RET_GONE); } WS_Reset(req->ws, NULL); WS_Reset(wrk->aws, NULL); if (HTTP1_Reinit(req->htc) == HTTP1_COMPLETE) { AZ(req->vsl->wid); req->t_first = req->t_req = sp->t_idle; wrk->stats->sess_pipeline++; req->acct.req_hdrbytes += Tlen(req->htc->rxbuf); return (SESS_DONE_RET_START); } else { if (Tlen(req->htc->rxbuf)) wrk->stats->sess_readahead++; return (SESS_DONE_RET_WAIT); } }