Clark Rawlins wrote ..
> Hello,
> 
> I have a client I need to handle post requests for that uses
> Content-Encoding: xml and Transfer-Encoding: chunked.
> 
> Now the Content-Encoding is no problem I plan on using sax to parse the
> content.  The chunked transfer encoding is where I have run into issues.
> 
> I tracked it down to the part of the mod-python code that handles
> reading the request body from apache.
> 
> In two places it uses:
> rc = ap_setup_client_block(self->request_rec, REQUEST_CHUNKED_ERROR);
> 
> As a test, I modified the code to use REQUEST_CHUNKED_DECHUNK and it
> worked great for me.  Now I imagine that this may cause some problems
> for scripts using mod-python to handle requests but I couldn't think of
> any that wouldn't already be quite serious with a request of MAX_INT
> length.  What if anything am I missing and if I am not, could this
> change be incorporated into the main tree?

To make it short, mod_python can't be made to handle chunked incoming
content from a client and the change you suggest will cause other problems.

This is because when using REQUEST_CHUNKED_DECHUNK it is important
that the read buffer be large enough to handle any chunk being read. Ie.,
from Apache source code:

 * 1. Call ap_setup_client_block() near the beginning of the request       
 *    handler. This will set up all the necessary properties, and will      
 *    return either OK, or an error code. If the latter, the module should
 *    return that error code. The second parameter selects the policy to
 *    apply if the request message indicates a body, and how a chunked
 *    transfer-coding should be interpreted. Choose one of
 *    
 *    REQUEST_NO_BODY          Send 413 error if message has any body
 *    REQUEST_CHUNKED_ERROR    Send 411 error if body without Content-Length
 *    REQUEST_CHUNKED_DECHUNK  If chunked, remove the chunks for me.  
 *    REQUEST_CHUNKED_PASS     If chunked, pass the chunk headers with body.
 *
 *    In order to use the last two options, the caller MUST provide a buffer
 *    large enough to hold a chunk-size line, including any extensions.

If chunked is used the mod_python source can't know what the buffer size
it would need to use is as that is going to be dependent on the higher level
application and what it is doing.

Thus a general purpose solution like mod_python can't be used and what is
really needed is a lower level Python interface to Apache API so you can control
things properly specific for your case. I have talked about the need for such
a better Python/Apache interface previously on the list but nothing public is
probably going to be available in that space in the near future.

BTW, I am basing this analysis on reading Apache code. If you are seeing
different results and things are working then I can only assume it is because
you are using read() with a size. If you use read() without a size, you will
probably not get any content. Even when specifying an argument you might
get problems as mod_python will always read up to that size and not simply
return what might be available at that time from a chunk.

Anyway, I'll have a think about the problem some more as will affect some other
code I am working on. :-)

Graham

> Index: src/requestobject.c
> ===================================================================
> --- src/requestobject.c       (revision 510030)
> +++ src/requestobject.c       (working copy)
> @@ -864,7 +864,7 @@
>      if (! self->request_rec->read_length) {
>  
>          /* then do some initial setting up */
> -        rc = ap_setup_client_block(self->request_rec, REQUEST_CHUNKED_ERROR);
> +        rc = ap_setup_client_block(self->request_rec, 
> REQUEST_CHUNKED_DECHUNK);
>          if(rc != OK) {
>              PyObject *val = PyInt_FromLong(rc);
>              if (val == NULL)
> @@ -964,7 +964,7 @@
>      if (! self->request_rec->read_length) {
>  
>          /* then do some initial setting up */
> -        rc = ap_setup_client_block(self->request_rec, REQUEST_CHUNKED_ERROR);
> +        rc = ap_setup_client_block(self->request_rec, 
> REQUEST_CHUNKED_DECHUNK);
>  
>          if (rc != OK) {
>              PyObject *val = PyInt_FromLong(rc);

Reply via email to