enum htc_status_e HTC_RxStuff(struct http_conn *htc, htc_complete_f *func, double *t1, double *t2, double ti, double tn, int maxbytes) { double tmo; double now; enum htc_status_e hs; ssize_t z; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); AN(htc->rfd); assert(*htc->rfd > 0); AN(htc->ws->r); AN(htc->rxbuf_b); assert(htc->rxbuf_b <= htc->rxbuf_e); assert(htc->rxbuf_e <= htc->ws->r); AZ(isnan(tn)); if (t1 != NULL) assert(isnan(*t1)); if (htc->rxbuf_e == htc->ws->r) { /* Can't work with a zero size buffer */ WS_ReleaseP(htc->ws, htc->rxbuf_b); return (HTC_S_OVERFLOW); } z = (htc->ws->r - htc->rxbuf_b); if (z < maxbytes) maxbytes = z; /* Cap maxbytes at available WS */ while (1) { now = VTIM_real(); AZ(htc->pipeline_b); AZ(htc->pipeline_e); assert(htc->rxbuf_e <= htc->ws->r); hs = func(htc); if (hs == HTC_S_OVERFLOW || hs == HTC_S_JUNK) { WS_ReleaseP(htc->ws, htc->rxbuf_b); return (hs); } if (hs == HTC_S_COMPLETE) { WS_ReleaseP(htc->ws, htc->rxbuf_e); /* Got it, run with it */ if (t1 != NULL && isnan(*t1)) *t1 = now; if (t2 != NULL) *t2 = now; return (HTC_S_COMPLETE); } if (hs == HTC_S_MORE) { /* Working on it */ if (t1 != NULL && isnan(*t1)) *t1 = now; } else if (hs == HTC_S_EMPTY) htc->rxbuf_e = htc->rxbuf_b; else WRONG("htc_status_e"); tmo = tn - now; if (!isnan(ti) && ti < tn && hs == HTC_S_EMPTY) tmo = ti - now; z = maxbytes - (htc->rxbuf_e - htc->rxbuf_b); if (z <= 0) { /* maxbytes reached but not HTC_S_COMPLETE. Return * overflow. */ WS_ReleaseP(htc->ws, htc->rxbuf_b); return (HTC_S_OVERFLOW); } if (tmo <= 0.0) tmo = 1e-3; z = VTCP_read(*htc->rfd, htc->rxbuf_e, z, tmo); if (z == 0 || z == -1) { WS_ReleaseP(htc->ws, htc->rxbuf_b); return (HTC_S_EOF); } else if (z > 0) htc->rxbuf_e += z; else if (z == -2) { if (hs == HTC_S_EMPTY && ti <= now) { WS_ReleaseP(htc->ws, htc->rxbuf_b); return (HTC_S_IDLE); } if (tn <= now) { WS_ReleaseP(htc->ws, htc->rxbuf_b); return (HTC_S_TIMEOUT); } } } }
enum htc_status_e HTC_RxStuff(struct http_conn *htc, htc_complete_f *func, double *t1, double *t2, double ti, double tn, int maxbytes) { double tmo; double now; enum htc_status_e hs; int i; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); AN(htc->ws->r); AN(htc->rxbuf_b); assert(htc->rxbuf_b <= htc->rxbuf_e); AZ(isnan(tn)); if (t1 != NULL) assert(isnan(*t1)); if (htc->rxbuf_e == htc->ws->r) { /* Can't work with a zero size buffer */ WS_ReleaseP(htc->ws, htc->rxbuf_b); return (HTC_S_OVERFLOW); } if ((htc->ws->r - htc->rxbuf_b) - 1L < maxbytes) maxbytes = (htc->ws->r - htc->rxbuf_b) - 1L; /* Space for NUL */ while (1) { now = VTIM_real(); AZ(htc->pipeline_b); AZ(htc->pipeline_e); assert(htc->rxbuf_e < htc->ws->r); *htc->rxbuf_e = '\0'; hs = func(htc); if (hs == HTC_S_OVERFLOW || hs == HTC_S_JUNK) { WS_ReleaseP(htc->ws, htc->rxbuf_b); return (hs); } if (hs == HTC_S_COMPLETE) { WS_ReleaseP(htc->ws, htc->rxbuf_e); /* Got it, run with it */ if (t1 != NULL && isnan(*t1)) *t1 = now; if (t2 != NULL) *t2 = now; return (HTC_S_COMPLETE); } if (hs == HTC_S_MORE) { /* Working on it */ if (t1 != NULL && isnan(*t1)) *t1 = now; } else if (hs == HTC_S_EMPTY) htc->rxbuf_e = htc->rxbuf_b; else WRONG("htc_status_e"); tmo = tn - now; if (!isnan(ti) && ti < tn) tmo = ti - now; i = maxbytes - (htc->rxbuf_e - htc->rxbuf_b); assert(i >= 0); if (i == 0) { WS_ReleaseP(htc->ws, htc->rxbuf_b); return (HTC_S_OVERFLOW); } if (tmo <= 0.0) tmo = 1e-3; i = VTCP_read(htc->fd, htc->rxbuf_e, i, tmo); if (i == 0 || i == -1) { WS_ReleaseP(htc->ws, htc->rxbuf_b); return (HTC_S_EOF); } else if (i > 0) htc->rxbuf_e += i; else if (i == -2) { if (hs == HTC_S_EMPTY && ti <= now) { WS_ReleaseP(htc->ws, htc->rxbuf_b); return (HTC_S_IDLE); } if (tn <= now) { WS_ReleaseP(htc->ws, htc->rxbuf_b); return (HTC_S_TIMEOUT); } } } }