static apr_status_t keepalive_read_chunk()

in flood_socket_keepalive.c [158:277]


static apr_status_t keepalive_read_chunk(response_t *resp,
                                         keepalive_socket_t *sock,
                                         int chunk_length,
                                         char **bp, int bplen)
{
    apr_status_t status = APR_SUCCESS;
    int old_length = 0;

    if (!resp->chunk) {
        chunk_length = 0;
    } else if (chunk_length < 0) {
        old_length = chunk_length;
        chunk_length = 0;
    } else if (chunk_length == 0) {
        return status;
    }

    do {
        /* Sentinel value */
        apr_size_t blen = 0;
        char *start_chunk, *end_chunk, *b;

        /* Always reset the b. */
        b = *bp;

        /* Time to read the next chunk size.  At this point,
         * we should be ready to read a CRLF followed by
         * a line that contains the next chunk size.
         */
        while (!chunk_length)
        {
            /* We are reading the next chunk and see a CRLF. */
            if (blen >= 1 && b[0] == '\r') {
                b++;
                blen--;
                if (blen >= 1 && b[0] == '\n') {
                    b++;
                    blen--;
                }
                else {
                    old_length = -1;
                }
            }

            /* If blen is 0, we're empty so read more data. */
            while (!blen)
            {
                /* Reset and read as much as we can. */
                blen = bplen;
                b = *bp;
                status = ksock_read_socket(sock, b, &blen);
                if (status != APR_SUCCESS) {
                    return status;
                }

                /* We got caught in the middle of a chunk last time. */ 
                if (old_length < 0) {
                    b -= old_length;
                    blen += old_length;
                    old_length = 0;
                }
                /* We are reading the next chunk and see a CRLF. */
                if (blen >= 2 && b[0] == '\r' && b[1] == '\n') {
                    b += 2;
                    blen -= 2;
                }
            }

            start_chunk = b;
            chunk_length = keepalive_read_chunk_size(start_chunk);

            /* last-chunk */
            if (!chunk_length)
            {
                /* See if we already read the trailer and final CRLF */
                end_chunk = strstr(b, CRLF CRLF);
                if (!end_chunk)
                {
                    /* Read as much as we can. */
                    blen = bplen;
                    b = *bp;
                    status = ksock_read_socket(sock, b, &blen);
                    if (status != APR_SUCCESS)
                        return status;
                }

                /* FIXME: If we add pipelining, we need to put
                 * the remainder back so that it can be read. */
                blen -= end_chunk - b + 4;

                return APR_SUCCESS;
            }

            /* If this fails, we're very unlikely to have read a chunk! */
            end_chunk = strstr(start_chunk, CRLF) + 2;
            blen -= end_chunk - b;

            /* Oh no, we read more than one chunk this go-around! */
            if (chunk_length <= blen) {
                b += chunk_length + (end_chunk - b);
                blen -= chunk_length;
                chunk_length = 0;
            }
            else
                chunk_length -= blen;
        }

        if (chunk_length > bplen)
            blen = bplen;
        else
            blen = chunk_length;

        status = ksock_read_socket(sock, b, &blen);

        chunk_length -= blen;
    }
    while (status == APR_SUCCESS);

    return APR_SUCCESS;
}