apr_status_t keepalive_recv_resp()

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