Hi,

It seems there's a bug in httpd with mod_apreq that causes all HTTP post requests sent with chunked transfer encoding to return with HTTP 400 bad request.
The problem was reported apreq-dev, and it's possible to patch mod_apreq, but it seems the problem is in ap_http_filter/ap_get_mime_headers which causes httpd to reenter the entire input filter chain twice.
See reply from apreq-dev at the end.


I'm using httpd-2.0.52 and libapreq2-2.04-dev. In my apache module I parse a
POST request using apreq. POST requests sent with content-length are parsed
OK, but when I POST using chunked transfer encoding I get HTTP 400 bad request.


The problem can be easily reproduced by using the code from the sample mod_apreq_request_test.c and using curl as shown below:

C:\Util\cURL>curl -D - -d "param1=a&param2=b" -H "Transfer-Encoding: chunked" http://localhost:8888/mq
HTTP/1.1 400 Bad Request
Date: Thu, 23 Dec 2004 17:34:35 GMT
Server: Apache/2.0.52 (Win32) DAV/2
Content-Length: 38
Connection: close
Content-Type: text/plain; charset=ISO-8859-1


ARGS:
BODY:
       param1 => a
       param2 => b


Note that HTTP 400 is returned, even though the module parsed the parameters OK and returned OK. As far as I can tell, curl is sending a valid request.

The same tests WITHOUT chunked encoding returns 200 OK:

C:\Util\cURL>curl -D - -d "param1=a&param2=b" http://localhost:8888/mq
HTTP/1.1 200 OK
Date: Thu, 23 Dec 2004 17:37:22 GMT
Server: Apache/2.0.52 (Win32) DAV/2
Content-Length: 38
Content-Type: text/plain; charset=ISO-8859-1

ARGS:
BODY:
       param1 => a
       param2 => b

I traced down the problem to:

apreq_filter(0x008bf778, 0x008bfc30, 1, 0, 0) line 558
ap_get_brigade(0x008bf778, 0x008bfc30, 1, 0, 0) line 475 + 32 bytes
ap_rgetline_core(0x00f3fc04, 8192, 0x00f3fbfc, 0x008bdd58, 0, 0x008bfc30)
line 215 + 27 bytes
ap_get_mime_headers_core(0x008bdd58, 0x008bfc30) line 688 + 36 bytes
ap_get_mime_headers(0x008bdd58) line 836
ap_http_filter(0x008bed58, 0x008bf920, 0, 0, 8192) line 1559
ap_get_brigade(0x008bed58, 0x008bf920, 0, 0, 8192) line 475 + 32 bytes
net_time_filter(0x008be9d0, 0x008bf920, 0, 0, 8192) line 3668
ap_get_brigade(0x008be9d0, 0x008bf920, 0, 0, 8192) line 475 + 32 bytes
apreq_filter(0x008bf778, 0x008bf920, 0, 0, 8192) line 578 + 35 bytes
ap_get_brigade(0x008bf778, 0x008bf920, 0, 0, 8192) line 475 + 32 bytes
apreq_request_test_handler(0x008bdd58) line 235 + 33 bytes
..

At mod_apreq.c:558 APR_ENOTIMPL is returned because mode is AP_MODE_GETLINE.
This causes r->status = HTTP_BAD_REQUEST; in protocol.c:1843 which eventually is returned to client.



Here's the reply from apreq-dev: -----------------

"Ron Avriel" <[EMAIL PROTECTED]> writes:

[...]

I traced down the problem to:

apreq_filter(0x008bf778, 0x008bfc30, 1, 0, 0) line 558
ap_get_brigade(0x008bf778, 0x008bfc30, 1, 0, 0) line 475 + 32 bytes
ap_rgetline_core(0x00f3fc04, 8192, 0x00f3fbfc, 0x008bdd58, 0,
0x008bfc30) line 215 + 27 bytes
ap_get_mime_headers_core(0x008bdd58, 0x008bfc30) line 688 + 36 bytes
ap_get_mime_headers(0x008bdd58) line 836
ap_http_filter(0x008bed58, 0x008bf920, 0, 0, 8192) line 1559
ap_get_brigade(0x008bed58, 0x008bf920, 0, 0, 8192) line 475 + 32 bytes
net_time_filter(0x008be9d0, 0x008bf920, 0, 0, 8192) line 3668
ap_get_brigade(0x008be9d0, 0x008bf920, 0, 0, 8192) line 475 + 32 bytes
apreq_filter(0x008bf778, 0x008bf920, 0, 0, 8192) line 578 + 35 bytes
ap_get_brigade(0x008bf778, 0x008bf920, 0, 0, 8192) line 475 + 32 bytes
apreq_request_test_handler(0x008bdd58) line 235 + 33 bytes

Notice that the httpd filter is reentering the entire input filter chain. This is a bug in ap_http_filter/ap_get_mime_headers; please report it to [EMAIL PROTECTED]

We can certainly work around it though; see if this patch helps.

Index: env/mod_apreq.c
===================================================================
--- env/mod_apreq.c (revision 123167)
+++ env/mod_apreq.c (working copy)
@@ -560,6 +560,8 @@
    case AP_MODE_EXHAUSTIVE:
        /* only the modes above are supported */
        break;
+    case AP_MODE_GETLINE: /* punt- chunks are b0rked in ap_http_filter */
+        return ap_get_brigade(f->next, bb, mode, block, readbytes);
    default:
        return APR_ENOTIMPL;
    }


-- Joe Schaefer -------------------- [end of apreq-dev reply]

Any help will be greatly appreciated.
Thanks,
Ron

Reply via email to