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???