I am writing filter for Apache/2.2.11. 
In the filter I want to read the POST data of the request. To achieve this I
written a code to read the data from brigade/bucket.
The code is working fine if "ap_get_brigade" api is called in
"AP_MODE_READBYTES" mode. I am able to read complete post data of the request.
But it is failing in case "ap_get_brigade" api is called in
"AP_MODE_SPECULATIVE" mode. Actually after reading post data in the filter, post
data should not be cleared and it should be accessible to downstream application
so I want to use AP_MODE_SPECULATIVE.
I found that in the failure case "ap_get_brigade" is returning the same chunk of
data. 

Here pasting the code snippet:


int printPost(request_rec* rqRec)
{
    apr_status_t retStatus;
    apr_bucket_brigade *bb;
    apr_bucket *bucket;
    ap_input_mode_t read_mode;
    int nread = 0;
    bool seen_eos=false;
    const char *data;
    apr_size_t len;
    int nBytes = 0;
                
    const char *contentLengthStr = apr_table_get(rqRec->headers_in,
"Content-Length");
    nBytes = atoi(contentLengthStr);
        
    fprintf(stderr,"\n URI:%s, content-length:%d", rqRec->uri,nBytes);
        
    char *  freep = (char *)malloc(nBytes + 1);
    char * qstr = freep;
    memset(qstr, 0, nBytes + 1);
        
    // Create a bucket brigade to fill data from the input filter
    bb = apr_brigade_create(rqRec->pool, rqRec->connection->bucket_alloc);

    read_mode = AP_MODE_SPECULATIVE;  //AP_MODE_READBYTES
    do
    {
    // Get the bucket brigade filled from the input filter
    retStatus = ap_get_brigade(rqRec->input_filters, bb, read_mode,
APR_BLOCK_READ, nBytes);
    if ( retStatus != APR_SUCCESS ){
       fprintf(stderr,"\n Failed ap_get_brigade");
       goto endhere; 
    }

    for (bucket = APR_BRIGADE_FIRST(bb);
        bucket != APR_BRIGADE_SENTINEL(bb);
        bucket = APR_BUCKET_NEXT(bucket)) 
     {
        data = NULL;
        len = 0;
        if (APR_BUCKET_IS_EOS(bucket)) {
            seen_eos = true;
            break;
        }

        if (APR_BUCKET_IS_FLUSH(bucket)) {
                continue;
        }

        // bucket_read function sets the data pointer to its internal buffer and
returns the len field
        retStatus = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
        if ( retStatus != APR_SUCCESS) {
           fprintf(stderr,"\n Failed apr_bucket_read");
           goto endhere; //return 0;
        }
                
        fprintf(stderr,"\n bucket->length :%d",bucket->length);
        fprintf(stderr,"\n nread:%d  len :%d op:%d, retStatus:%d", nread, (int
)len, (nread + (int )len >nBytes),(int)retStatus);
        char * tp = (char *)malloc((int )len + 1);
        memset(tp, 0, len + 1);
        memcpy(tp, data, len);
        fprintf(stderr,"\n DATA from the current bucket :%s",tp);
        free(tp);
                
        if (nread + (int )len > nBytes) {
                fprintf(stderr,"\n Too much POST data: %s", rqRec->uri);        
                                        
                seen_eos = true;
                break;
        }

        memcpy(qstr, data, len);
        qstr += len;
        nread += len;

        if (nread == nBytes)
        {
           seen_eos = true;
           break;
        }
     }/* End of For loop*/
    apr_brigade_cleanup(bb);
    }
    while (!seen_eos);

endhere:
        fprintf(stderr,"\n FINAL POST DATA :%s",freep);
    free(freep);
    return nread;
}
 
 
If I post some data, output  looks like:

 URI:/test.cgi, content-length:5537
 bucket->length :764
 nread:0  len :764 op:0, retStatus:0
 DATA from the current bucket :post_data=start1111............................
 bucket->length :764
 nread:764  len :764 op:0, retStatus:0
 DATA from the current bucket :post_data=start1111............................
 bucket->length :764
 nread:1528  len :764 op:0, retStatus:0
 DATA from the current bucket :post_data=start1111............................
 bucket->length :764
 nread:2292  len :764 op:0, retStatus:0
 DATA from the current bucket :post_data=start1111............................
 bucket->length :764
 nread:3056  len :764 op:0, retStatus:0
 DATA from the current bucket :post_data=start1111............................
 bucket->length :764
 nread:3820  len :764 op:0, retStatus:0
 DATA from the current bucket :post_data=start1111............................
 bucket->length :764
 nread:4584  len :764 op:0, retStatus:0
 DATA from the current bucket :post_data=start1111............................
 bucket->length :764
 nread:5348  len :764 op:1, retStatus:0
 DATA from the current bucket :post_data=start1111............................
 Too much POST data: /test.cgi
 FINAL POST DATA
:post_data=start1111....111post_data=start11111....1111post_data=start111111.
...111post_data=start11111....1post_data=start111....111post_data=start11111.
...1111post_data=start111111......
 
 
 In the above code, If I change the read_mode to AP_MODE_READBYTES and post the
same request, output looks like:
 
 URI:/test.cgi, content-length:5537
 bucket->length :2024
 nread:0  len :2024 op:0, retStatus:0
 DATA from the current bucket :post_data=start11111............................
 bucket->length :1260
 nread:2024  len :1260 op:0, retStatus:0
 DATA from the current bucket :111111111111111.............................
 bucket->length :2253
 nread:3284  len :2253 op:0, retStatus:0
 DATA from the current bucket :111111111.........................1111111End
 FINAL POST DATA
:post_data=start11111111111111.........................1111111111111111End
 
 
Using same code and setting read_mode to AP_MODE_SPECULATIVE, on windows
platform issue is not seen.
Issue is seen on Linux & Linux64 of RHEL4 version. 
Is there anything wrong in my implementation or else anything???

Reply via email to