int HTC_Rx(struct http_conn *htc) { int i; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); AN(htc->ws->r); i = (htc->ws->r - htc->rxbuf.e) - 1; /* space for NUL */ if (i <= 0) { WS_ReleaseP(htc->ws, htc->rxbuf.b); return (-2); } i = read(htc->fd, htc->rxbuf.e, i); if (i <= 0) { /* * We wouldn't come here if we had a complete HTTP header * so consequently an EOF can not be OK */ WS_ReleaseP(htc->ws, htc->rxbuf.b); return (-1); } htc->rxbuf.e += i; *htc->rxbuf.e = '\0'; return (HTC_Complete(htc)); }
enum htc_status_e HTTP1_Rx(struct http_conn *htc) { int i; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); AN(htc->ws->r); AZ(htc->pipeline.b); AZ(htc->pipeline.e); i = (htc->ws->r - htc->rxbuf.e) - 1; /* space for NUL */ if (i <= 0) { WS_ReleaseP(htc->ws, htc->rxbuf.b); return (HTTP1_OVERFLOW); } i = read(htc->fd, htc->rxbuf.e, i); if (i <= 0) { /* * We wouldn't come here if we had a complete HTTP header * so consequently an EOF can not be OK */ WS_ReleaseP(htc->ws, htc->rxbuf.b); return (HTTP1_ERROR_EOF); } htc->rxbuf.e += i; *htc->rxbuf.e = '\0'; return (HTTP1_Complete(htc)); }
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); }
int HTC_Rx(struct http_conn *htc) { int i; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); AN(htc->ws->r); i = (htc->ws->r - htc->rxbuf.e) - 1; /* space for NUL */ if (i <= 0) { WS_ReleaseP(htc->ws, htc->rxbuf.b); return (-2); } i = read(htc->fd, htc->rxbuf.e, i); if (i <= 0) { WS_ReleaseP(htc->ws, htc->rxbuf.b); return (-1); } htc->rxbuf.e += i; *htc->rxbuf.e = '\0'; return (HTC_Complete(htc)); }
int HTC_RxNoCompleteCheck(struct http_conn *htc) { int i; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); AN(htc->ws->r); i = (htc->ws->r - htc->rxbuf.e) - 1; /* space for NUL */ if (i <= 0) { WS_ReleaseP(htc->ws, htc->rxbuf.b); return (-2); } i = CFD_read(&htc->fds, htc->rxbuf.e, i); if (i == -2) return (1); if (i <= 0) { WS_ReleaseP(htc->ws, htc->rxbuf.b); return (-1); } htc->rxbuf.e += i; *htc->rxbuf.e = '\0'; return (0); }
int HTC_Complete(struct http_conn *htc) { int i; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); i = htc_header_complete(&htc->rxbuf); assert(i >= 0); if (i == 0) return (0); WS_ReleaseP(htc->ws, htc->rxbuf.e); if (htc->rxbuf.b + i < htc->rxbuf.e) { htc->pipeline.b = htc->rxbuf.b + i; htc->pipeline.e = htc->rxbuf.e; htc->rxbuf.e = htc->pipeline.b; } return (1); }
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); }
/* Possible error returns: * * H2E_COMPRESSION_ERROR: Lost compression state due to incomplete header * block. This is a connection level error. * * H2E_ENHANCE_YOUR_CALM: Ran out of workspace or http header space. This * is a stream level error. */ int h2h_decode_fini(const struct h2_sess *h2, struct h2h_decode *d) { int ret; CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); CHECK_OBJ_NOTNULL(h2->new_req, REQ_MAGIC); CHECK_OBJ_NOTNULL(d, H2H_DECODE_MAGIC); WS_ReleaseP(h2->new_req->http->ws, d->out); if (d->vhd_ret != VHD_OK) { /* HPACK header block didn't finish at an instruction boundary */ VSLb(h2->new_req->http->vsl, SLT_BogoHeader, "HPACK compression error (%s)", VHD_Error(d->vhd_ret)); ret = H2E_COMPRESSION_ERROR; } else ret = d->error; d->magic = 0; return (ret); }
enum http1_status_e HTTP1_Complete(struct http_conn *htc) { char *p; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); AZ(htc->pipeline_b); AZ(htc->pipeline_e); assert(htc->rxbuf_e >= htc->rxbuf_b); assert(*htc->rxbuf_e == '\0'); /* Skip any leading white space */ for (p = htc->rxbuf_b ; vct_islws(*p); p++) continue; if (p == htc->rxbuf_e) { /* All white space */ htc->rxbuf_e = htc->rxbuf_b; *htc->rxbuf_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, htc->rxbuf_e); if (p < htc->rxbuf_e) { htc->pipeline_b = p; htc->pipeline_e = htc->rxbuf_e; htc->rxbuf_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); }
int V1F_FetchRespHdr(struct busyobj *bo) { struct http *hp; enum htc_status_e hs; int first; struct http_conn *htc; CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); CHECK_OBJ_NOTNULL(bo->htc, HTTP_CONN_MAGIC); CHECK_OBJ_ORNULL(bo->req, REQ_MAGIC); htc = bo->htc; VSC_C_main->backend_req++; /* Receive response */ SES_RxInit(htc, bo->ws, cache_param->http_resp_size, cache_param->http_resp_hdr_len); CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); CHECK_OBJ_NOTNULL(bo->htc, HTTP_CONN_MAGIC); VTCP_set_read_timeout(htc->fd, htc->first_byte_timeout); first = 1; do { hs = SES_Rx(htc, 0); if (hs == HTC_S_MORE) hs = HTTP1_Complete(htc); if (hs == HTC_S_OVERFLOW) { WS_ReleaseP(htc->ws, htc->rxbuf_b); bo->acct.beresp_hdrbytes += htc->rxbuf_e - htc->rxbuf_b; VSLb(bo->vsl, SLT_FetchError, "http %sread error: overflow", first ? "first " : ""); htc->doclose = SC_RX_OVERFLOW; return (-1); } if (hs == HTC_S_EOF) { WS_ReleaseP(htc->ws, htc->rxbuf_b); bo->acct.beresp_hdrbytes += htc->rxbuf_e - htc->rxbuf_b; VSLb(bo->vsl, SLT_FetchError, "http %sread error: EOF", first ? "first " : ""); htc->doclose = SC_RX_TIMEOUT; return (first ? 1 : -1); } if (first) { first = 0; VTCP_set_read_timeout(htc->fd, htc->between_bytes_timeout); } } while (hs != HTC_S_COMPLETE); bo->acct.beresp_hdrbytes += htc->rxbuf_e - htc->rxbuf_b; hp = bo->beresp; if (HTTP1_DissectResponse(hp, htc)) { VSLb(bo->vsl, SLT_FetchError, "http format error"); htc->doclose = SC_RX_JUNK; return (-1); } htc->doclose = http_DoConnection(hp); return (0); }
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); } } } }
static int cnt_lookup(struct sess *sp) { struct objcore *oc; struct object *o; struct objhead *oh; struct worker *wrk; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); wrk = sp->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC); AZ(wrk->busyobj); if (sp->hash_objhead == NULL) { /* Not a waiting list return */ AZ(sp->vary_b); AZ(sp->vary_l); AZ(sp->vary_e); (void)WS_Reserve(sp->ws, 0); } else { AN(sp->ws->r); } sp->vary_b = (void*)sp->ws->f; sp->vary_e = (void*)sp->ws->r; sp->vary_b[2] = '\0'; oc = HSH_Lookup(sp, &oh); if (oc == NULL) { /* * We lost the session to a busy object, disembark the * worker thread. The hash code to restart the session, * still in STP_LOOKUP, later when the busy object isn't. * NB: Do not access sp any more ! */ return (1); } CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC); /* If we inserted a new object it's a miss */ if (oc->flags & OC_F_BUSY) { wrk->stats.cache_miss++; if (sp->vary_l != NULL) { assert(oc->busyobj->vary == sp->vary_b); VRY_Validate(oc->busyobj->vary); WS_ReleaseP(sp->ws, (void*)sp->vary_l); } else { AZ(oc->busyobj->vary); WS_Release(sp->ws, 0); } sp->vary_b = NULL; sp->vary_l = NULL; sp->vary_e = NULL; wrk->objcore = oc; CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC); sp->step = STP_MISS; return (0); } o = oc_getobj(wrk, oc); CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC); wrk->obj = o; WS_Release(sp->ws, 0); sp->vary_b = NULL; sp->vary_l = NULL; sp->vary_e = NULL; if (oc->flags & OC_F_PASS) { wrk->stats.cache_hitpass++; WSP(sp, SLT_HitPass, "%u", wrk->obj->xid); (void)HSH_Deref(wrk, NULL, &wrk->obj); wrk->objcore = NULL; sp->step = STP_PASS; return (0); } wrk->stats.cache_hit++; WSP(sp, SLT_Hit, "%u", wrk->obj->xid); sp->step = STP_HIT; return (0); }
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); }
enum htc_status_e SES_RxReq(const struct worker *wrk, struct req *req, htc_complete_f *func) { double tmo; double now, when; struct sess *sp; enum htc_status_e hs; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); sp = req->sp; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); AZ(isnan(sp->t_idle)); assert(isnan(req->t_first)); when = sp->t_idle + cache_param->timeout_idle; tmo = cache_param->timeout_linger; while (1) { hs = SES_Rx(req->htc, tmo); now = VTIM_real(); if (hs == HTC_S_EOF) { WS_ReleaseP(req->htc->ws, req->htc->rxbuf_b); return (HTC_S_CLOSE); } if (hs == HTC_S_OVERFLOW) { WS_ReleaseP(req->htc->ws, req->htc->rxbuf_b); return (HTC_S_OVERFLOW); } hs = func(req->htc); if (hs == HTC_S_OVERFLOW) { WS_ReleaseP(req->htc->ws, req->htc->rxbuf_b); return (HTC_S_OVERFLOW); } if (hs == HTC_S_JUNK) { WS_ReleaseP(req->htc->ws, req->htc->rxbuf_b); return (HTC_S_JUNK); } if (hs == HTC_S_COMPLETE) { /* Got it, run with it */ if (isnan(req->t_first)) req->t_first = now; req->t_req = now; return (HTC_S_COMPLETE); } if (when < now) return (HTC_S_TIMEOUT); if (hs == HTC_S_MORE) { /* Working on it */ if (isnan(req->t_first)) req->t_first = now; tmo = when - now; continue; } assert(hs == HTC_S_EMPTY); /* Nothing but whitespace */ tmo = sp->t_idle + cache_param->timeout_linger - now; if (tmo < 0) return (HTC_S_IDLE); } }
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); }
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); } } } }