Apache ap_get_brigade() do loop necessity

56 Views Asked by At

The Apache Modules Book has the following piece of code in it:

apr_status_t status;
int end = 0;
apr_size_t bytes, count = 0;
const char *buf;
apr_bucket *b;
apr_bucket_brigade *bb;

/* OK, we have some input data. Now read and count it. */
/* Create a brigade to put the data into. */
bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
do {
    /* Read a chunk of input into bb */
    status = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
    APR_BLOCK_READ, BUFLEN);
    if ( status == APR_SUCCESS ) {
        /* Loop over the contents of bb */
        for (b = APR_BRIGADE_FIRST(bb);
        b != APR_BRIGADE_SENTINEL(bb);
        b = APR_BUCKET_NEXT(b) ) {
            /* Check for EOS */
            if (APR_BUCKET_IS_EOS(b)) {
            end = 1;
            break;
            } else if (APR_BUCKET_IS_METADATA(b)) {
                continue;
            }
            /* To get the actual length, we need to read the data */
            bytes = BUFLEN;
            status = apr_bucket_read(b, &buf, &bytes, 
            APR_BLOCK_READ);
            count += bytes;
        }
    }
    /* Discard data we're finished with */
    apr_brigade_cleanup(bb);
} while (!end && (status == APR_SUCCESS));

mod_cgi.c, amongst others (in the Apache source code), contains something similar:

do {
        apr_bucket *bucket;

        rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
                            APR_BLOCK_READ, HUGE_STRING_LEN);

        if (rv != APR_SUCCESS) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01225)
                          "Error reading request entity data");
            return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
        }

        for (bucket = APR_BRIGADE_FIRST(bb);
             bucket != APR_BRIGADE_SENTINEL(bb);
             bucket = APR_BUCKET_NEXT(bucket))
        {
            const char *data;
            apr_size_t len;

            if (APR_BUCKET_IS_EOS(bucket)) {
                seen_eos = 1;
                break;
            }

            /* We can't do much with this. */
            if (APR_BUCKET_IS_FLUSH(bucket)) {
                continue;
            }

            /* If the child stopped, we still must read to EOS. */
            if (child_stopped_reading) {
                continue;
            }

            /* read */
            apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);

            if (conf->logname && dbpos < conf->bufbytes) {
                int cursize;

                if ((dbpos + len) > conf->bufbytes) {
                    cursize = conf->bufbytes - dbpos;
                }
                else {
                    cursize = len;
                }
                memcpy(dbuf + dbpos, data, cursize);
                dbpos += cursize;
            }

            /* Keep writing data to the child until done or too much time
             * elapses with no progress or an error occurs.
             */
            rv = apr_file_write_full(script_out, data, len, NULL);

            if (rv != APR_SUCCESS) {
                /* silly script stopped reading, soak up remaining message */
                child_stopped_reading = 1;
            }
        }
        apr_brigade_cleanup(bb);
    }
    while (!seen_eos);

The question is - what is the point of the do/while loop here? If we don't find eos/seen_eos inside the for loop we're apparently going to get back to ap_get_brigade. Wouldn't the arguments passed (and consequently the outcome) remain the same? And if so, can't we safely do away with the do/while loop?

Thanks.

0

There are 0 best solutions below