in flood_socket_keepalive.c [342:544]
apr_status_t keepalive_recv_resp(response_t **resp, socket_t *sock, apr_pool_t *pool)
{
keepalive_socket_t *ksock = (keepalive_socket_t *)sock;
char *cl, *ecl, cls[17];
char *current_line;
apr_size_t i;
response_t *new_resp;
apr_status_t status;
long content_length = 0, chunk_length;
const char *header;
new_resp = apr_pcalloc(pool, sizeof(response_t));
new_resp->rbuftype = POOL;
new_resp->rbufsize = MAX_DOC_LENGTH - 1;
new_resp->rbuf = apr_palloc(pool, new_resp->rbufsize);
status = ksock_read_socket(ksock, new_resp->rbuf, &new_resp->rbufsize);
if (status != APR_SUCCESS && status != APR_EOF) {
return status;
}
/* FIXME: Assume we got the full header for now. */
new_resp->headers = apr_table_make(pool, 25);
current_line = new_resp->rbuf;
do {
char *end_of_line, *header_end, *header_key, *header_val;
int line_length, key_length;
end_of_line = strstr(current_line, CRLF);
if (!end_of_line || end_of_line == current_line) {
break;
}
line_length = end_of_line - current_line;
header_end = memchr(current_line, ':', line_length);
if (header_end) {
key_length = header_end - current_line;
header_key = apr_pstrmemdup(pool, current_line, key_length);
header_val = apr_pstrmemdup(pool, current_line + key_length + 2,
line_length - key_length - 2);
apr_table_set(new_resp->headers, header_key, header_val);
}
current_line += line_length + sizeof(CRLF) - 1;
}
while((current_line - new_resp->rbuf) < new_resp->rbufsize);
/* If this exists, we aren't keepalive anymore. */
header = apr_table_get(new_resp->headers, "Connection");
if (header && !strcasecmp(header, "Close")) {
new_resp->keepalive = 0;
}
else {
new_resp->keepalive = 1;
}
/* If we have a HEAD request, we shouldn't be receiving a body. */
if (ksock->method == HEAD) {
*resp = new_resp;
return APR_SUCCESS;
}
header = apr_table_get(new_resp->headers, "Transfer-Encoding");
if (header && !strcasecmp(header, "Chunked"))
{
new_resp->chunked = 1;
new_resp->chunk = NULL;
chunk_length = 0;
/* Find where headers ended */
cl = current_line;
if (cl) {
/* Skip over the CRLF chars */
cl += sizeof(CRLF)-1;
}
/* We have a partial chunk and we aren't at the end. */
if (cl && *cl && (cl - (char*)new_resp->rbuf) < new_resp->rbufsize) {
int remaining;
do {
if (new_resp->chunk) {
/* If we have enough space to skip over the ending CRLF,
* do so. */
if (chunk_length + 2 <= remaining) {
new_resp->chunk += chunk_length + 2;
}
else {
/* We got more than a chunk, but not the full CRLF. */
chunk_length = -(remaining - chunk_length);
remaining = 0;
break;
}
}
else {
new_resp->chunk = cl;
}
if ((new_resp->chunk - (char*)new_resp->rbuf) <
new_resp->rbufsize && *new_resp->chunk) {
char *foo;
chunk_length = keepalive_read_chunk_size(new_resp->chunk);
/* Search for the beginning of the chunk. */
foo = strstr(new_resp->chunk, CRLF);
assert(foo);
new_resp->chunk = foo + 2;
remaining = new_resp->rbufsize -
(int)(new_resp->chunk -
(char*)new_resp->rbuf);
}
else {
new_resp->chunk = NULL;
remaining = 0;
}
}
while (remaining > chunk_length);
chunk_length -= remaining;
}
}
else
{
header = apr_table_get(new_resp->headers, "Content-Length");
if (!header)
{
new_resp->keepalive = 0;
}
if (header)
{
cl = (char*)header;
ecl = cl + strlen(cl);
if (ecl && ecl - cl < 16)
{
strncpy(cls, cl, ecl - cl);
cls[ecl-cl] = '\0';
content_length = strtol(cls, &ecl, 10);
if (*ecl != '\0')
new_resp->keepalive = 0;
}
}
if (new_resp->keepalive)
{
/* Find where we ended */
ecl = current_line;
/* We didn't get full headers. Crap. */
if (!ecl)
new_resp->keepalive = 0;
{
ecl += sizeof(CRLF) - 1;
content_length -= new_resp->rbufsize - (ecl - (char*)new_resp->rbuf);
}
}
}
if (ksock->wantresponse)
{
if (new_resp->keepalive)
status = keepalive_load_resp(new_resp, ksock, content_length, pool);
else
status = keepalive_load_resp(new_resp, ksock, 0, pool);
}
else
{
char *b = apr_palloc(pool, MAX_DOC_LENGTH);
if (new_resp->chunked)
{
status = keepalive_read_chunk(new_resp, ksock, chunk_length,
&b, MAX_DOC_LENGTH - 1);
}
else if (new_resp->keepalive)
{
while (content_length && status != APR_EGENERAL &&
status != APR_EOF && status != APR_TIMEUP) {
if (content_length > MAX_DOC_LENGTH - 1)
i = MAX_DOC_LENGTH - 1;
else
i = content_length;
status = ksock_read_socket(ksock, b, &i);
content_length -= i;
}
}
else
{
while (status != APR_EGENERAL && status != APR_EOF &&
status != APR_TIMEUP) {
i = MAX_DOC_LENGTH - 1;
status = ksock_read_socket(ksock, b, &i);
}
}
}
*resp = new_resp;
return APR_SUCCESS;
}