agoo_con_http_read(agooCon c) {
    ssize_t	cnt = 0;

    if (c->dead || 0 == c->sock || c->closing) {
	return true;
    }
    if (AGOO_CON_HTTPS == c->bind->kind) {
#ifdef HAVE_OPENSSL_SSL_H
	if (NULL != c->req) {
	    cnt = SSL_read(c->ssl, c->req->msg + c->bcnt, (int)(c->req->mlen - c->bcnt));
	} else {
	    cnt = SSL_read(c->ssl, c->buf + c->bcnt, (int)(sizeof(c->buf) - c->bcnt - 1));
	}
	if (0 > cnt) {
	    //unsigned long	e = ERR_get_error();
	    int		e = (int)ERR_get_error();

	    if (0 == e) {
		return false;
	    } else {
		con_ssl_error(c, "read", (unsigned long)e, __FILE__, __LINE__);
		c->dead = true;
		return true;
	    }
	}
#else
	agoo_log_cat(&agoo_error_cat, "SSL not included in the build.");
	c->dead = true;
#endif
    } else {
	if (NULL != c->req) {
	    cnt = recv(c->sock, c->req->msg + c->bcnt, c->req->mlen - c->bcnt, 0);
	} else {
	    cnt = recv(c->sock, c->buf + c->bcnt, sizeof(c->buf) - c->bcnt - 1, 0);
	}
    }
    c->timeout = dtime() + CON_TIMEOUT;
    if (0 >= cnt) {
	// If nothing read then no need to complain. Just close.
	if (0 < c->bcnt) {
	    if (0 == cnt) {
		agoo_log_cat(&agoo_warn_cat, "Nothing to read. Client closed socket on connection %llu.", (unsigned long long)c->id);
	    } else {
		agoo_log_cat(&agoo_warn_cat, "Failed to read request. %s.", strerror(errno));
	    }
	}
	c->dead = true;
	return true;
    }
    c->bcnt += cnt;
    while (true) {
	if (NULL == c->req) {
	    size_t	mlen;

	    switch (con_header_read(c, &mlen)) {
	    case HEAD_AGAIN:
		// Try again the next time. Didn't read enough.
		return false;
	    case HEAD_OK:
		// req was created
		break;
	    case HEAD_HANDLED:
		if (mlen < c->bcnt) {
		    memmove(c->buf, c->buf + mlen, c->bcnt - mlen);
		    c->bcnt -= mlen;
		    // req is NULL so try to ready the header on the next request.
		    continue;
		} else {
		    c->bcnt = 0;
		    *c->buf = '\0';

		    return false;
		}
		break;
	    case HEAD_ERR:
	    default:
		c->bcnt = 0;
		*c->buf = '\0';

		return false;
	    }
	}
	if (NULL != c->req) {
	    if (c->req->mlen <= c->bcnt) {
		agooReq	req;
		agooRes	res;
		long	mlen;

		if (agoo_debug_cat.on && NULL != c->req && NULL != c->req->body.start) {
		    agoo_log_cat(&agoo_debug_cat, "%s request on %llu: %s", agoo_con_kind_str(c->bind->kind), (unsigned long long)c->id, c->req->body.start);
		}
		if (NULL == (res = agoo_res_create(c))) {
		    c->req = NULL;
		    agoo_log_cat(&agoo_error_cat, "memory allocation of response failed on connection %llu.", (unsigned long long)c->id);
		    return bad_request(c, 500, __LINE__);
		} else {
		    agoo_con_res_append(c, res);
		    res->close = should_close(c->req->header.start, c->req->header.len);
		    if (res->close) {
			c->closing = true;
		    }
		}
		c->req->res = res;
		mlen = c->req->mlen;
		check_upgrade(c);
		req = c->req;
		c->req = NULL;
		if (req->hook->no_queue && FUNC_HOOK == req->hook->type) {
		    req->hook->func(req);
		    agoo_req_destroy(req);
		} else {
		    agoo_queue_push(req->hook->queue, (void*)req);
		}
		if (mlen < (long)c->bcnt) {
		    memmove(c->buf, c->buf + mlen, c->bcnt - mlen);
		    c->bcnt -= mlen;
		} else {
		    c->bcnt = 0;
		    *c->buf = '\0';
		    break;
		}
		continue;
	    }
	}
	break;
    }
    return false;
}