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));
}
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);
}
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));
}