I just wanted to reply to add some more information as well as a proposed fix.

There are two problems with the code in axis2c (at least v 1.6.0).  
Specifically the file src/core/transport/http/server/apache2/apache_stream.c.  
The first problem is apache_stream_read does not properly handle return codes 
from ap_get_client_block.  The variable used to store the return code is of 
size_t, which is unsigned in most instances, and ap_get_client_block returns -1 
on error.  This can cause a segmentation fault when input filters are being 
used (in my case, mod_deflate).  This shouldn't cause any problems if no input 
filter is being used.  The fix for this is changing the variable that holds the 
return code from a size_t to ssize_t.

The second problem is a bit more complicated.  apache2_stream_read is 
implemented without taking into consideration that an input filter might not 
produce any output for the given number of input bytes passed to it.  A perfect 
example is the mod_deflate filter.  When sending compressed soap requests to 
axis2c, apache2_stream_read calls ap_get_client_block from httpd 
(http_filters.c) to get the next x bytes of filtered data to process.  In my 
tests, the first call to this requests 3 bytes of data.  So, mod_deflate gets 
called and is passed three bytes of data.  These three bytes of data are not 
enough to produce any output bytes, so the module returns that it produced zero 
bytes.  This then gets bubbled up to apache2_stream_read which interprets this 
as an end of stream.  And blam, decompression stops, and the request body is 
empty.

The problem can be fixed by making ap_get_client_block to recognize the 
scenario when no output data is produced and to continue sending data to the 
input filters until at least some data (or the true end of stream) is found.  
However, ap_get_client_block is within httpd and it itself isn't the issue.  So 
creating a similar version of ap_get_client_block that handles this scenario 
and resides within the axis2c domain is most likely the preferred method.

I have patched my version of the code and tested compressed and non-compressed 
requests with success.  I am really unfamiliar with a lot of the source (as 
well as httpd's) so I am worried there might be side-effects that I am not 
aware of.

The changes I used are as follows (any comments or suggestions are greatly 
appreciated).  I hope this might help someone else.


--- src/core/transport/http/server/apache2/apache2_stream.c     2009-08-21 
16:34:51.000000000 -0600
+++ src/core/transport/http/server/apache2/apache2_stream.c.murph       
2009-08-21 16:59:50.000000000 -0600
@@ -1,4 +1,3 @@
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -55,6 +54,11 @@
     axutil_stream_t * stream,
     const axutil_env_t * env);
 
+AP_DECLARE(long) apache2_ap_get_client_block(
+    request_rec *r,
+    char* buffer, 
+    apr_size_t bufsiz);
+
 AXIS2_EXTERN axutil_stream_t *AXIS2_CALL
 axutil_stream_create_apache2(
     const axutil_env_t * env,
@@ -94,15 +98,16 @@
     size_t count)
 {
     apache2_stream_impl_t *stream_impl = NULL;
-    size_t read = 0;
+    ssize_t read = 0;
     size_t len = 0;
+
     AXIS2_ENV_CHECK(env, AXIS2_CRITICAL_FAILURE);
 
     stream_impl = AXIS2_INTF_TO_IMPL(stream);
 
     while (count - len > 0)
     {
-        read = ap_get_client_block(stream_impl->request, (char *) buffer + len,
+        read = apache2_ap_get_client_block(stream_impl->request, (char *) 
buffer + len,
                                    count - len);
         if (read > 0)
         {
@@ -159,7 +164,7 @@
         AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
         return -1;
     }
-    len = ap_get_client_block(stream_impl->request, tmp_buffer, count);
+    len = apache2_ap_get_client_block(stream_impl->request, tmp_buffer, count);
     AXIS2_FREE(env->allocator, tmp_buffer);
     return len;
 
@@ -184,3 +189,99 @@
     AXIS2_ENV_CHECK(env, AXIS2_CRITICAL_FAILURE);
     return AXIS2_INTF_TO_IMPL(stream)->stream_type;
 }
+
+/*
+ * This is a re-write of get_client_block found in http_filters.c in httpd
+ * which does not work when dealing with compressed payloads (or any other 
input
+ * filters that could potentially return 0 bytes of filtered data and not be at
+ * the end of the stream).
+ * get_client_block is called in a loop to get the request message body.
+ * This is quite simple if the client includes a content-length
+ * (the normal case), but gets messy if the body is chunked. Note that
+ * r->remaining is used to maintain state across calls and that
+ * r->read_length is the total number of bytes given to the caller
+ * across all invocations.  It is messy because we have to be careful not
+ * to read past the data provided by the client, since these reads block.
+ * Returns 0 on End-of-body, -1 on error or premature chunk end.
+ *
+ */
+AP_DECLARE(long) apache2_ap_get_client_block (request_rec *r, char *buffer,
+        apr_size_t bufsiz)
+{
+    apr_status_t rv;
+    apr_bucket_brigade *bb;
+    int loop = 1;
+    int origBufSize = bufsiz;
+
+    if (r->remaining < 0 || (!r->read_chunked && r->remaining == 0)) {
+        return 0;
+    }
+
+    bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+    if (bb == NULL) {
+        r->connection->keepalive = AP_CONN_CLOSE;
+        return -1;
+    }
+
+    /* we need to loop until the input filters (if any) give us data */
+    while (loop) {
+        rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
+                APR_BLOCK_READ, bufsiz);
+
+        /* We lose the failure code here.  This is why ap_get_client_block 
should
+         * not be used.
+         */
+        if (rv != APR_SUCCESS) {
+            /* if we actually fail here, we want to just return and
+             * stop trying to read data from the client.
+             */
+            r->connection->keepalive = AP_CONN_CLOSE;
+            apr_brigade_destroy(bb);
+            return -1;
+        }
+
+        /* If this fails, it means that a filter is written incorrectly and 
that
+         * it needs to learn how to properly handle APR_BLOCK_READ requests by
+         * returning data when requested.
+         */
+        AP_DEBUG_ASSERT(!APR_BRIGADE_EMPTY(bb));
+
+        /* Check to see if EOS in the brigade.
+         *
+         * If so, we have to leave a nugget for the *next* ap_get_client_block
+         * call to return 0.
+         */
+        if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
+            if (r->read_chunked) {
+                r->remaining = -1;
+            } else {
+                r->remaining = 0;
+            }
+        }
+
+        rv = apr_brigade_flatten(bb, buffer, &bufsiz);
+        if (rv != APR_SUCCESS) {
+            apr_brigade_destroy(bb);
+            return -1;
+        }
+
+        /* XXX yank me? */
+        r->read_length += bufsiz;
+
+        /* it is possible that the entire bucket brigade is exhausted, but no 
data
+         * has been produced by the input filter (mod_deflate, for example)....
+         * in this scenario, we really need to keep looping
+         */
+        if (bufsiz != 0 || r->remaining <= 0) {
+            loop = 0;
+            apr_brigade_destroy(bb);
+        } else {
+            if (bufsiz == 0) {
+                bufsiz = origBufSize;
+            }
+        }
+
+    }
+
+    return bufsiz;
+}


-----Original Message-----
From: Murphey McCloy [mailto:mmcc...@webroot.com]
Sent: Fri 8/21/2009 10:33 AM
To: axis-c-user@ws.apache.org
Subject: Questions about using mod_deflate
 
Hello,

 

I am hoping someone might be able to help me out with a problem I am having.  I 
am using Axis2/C 1.6 with http 2.2.3 on CentOS 5.3.  I am attempting to use 
mod_deflate to decompress/compress my requests and responses.  It is handling 
compressing my responses just fine, but the requests are failing.  It appears 
to me that the decompression of the requests prematurely ends after the gzip 
header is validated.  Has anyone actually set axis2c and apache up to 
decompress incoming requests that could give me some guidance?

 

Thanks,

 

Murphey

 




<<winmail.dat>>

Reply via email to