You are viewing a plain text version of this content. The canonical link for it is here.
Posted to c-commits@axis.apache.org by ro...@apache.org on 2026/08/28 20:55:10 UTC

(axis-axis2-c-core) branch master updated (532bd75dc -> 727677f2d)

This is an automated email from the ASF dual-hosted git repository.

robertlazarski pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-c-core.git


    from 532bd75dc Turn on -Wsign-compare so the signed length stays readable
     new e379cb7bf Write the whole chunk the chunk header announced
     new 727677f2d Remove the unused prepend stream free function

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/core/transport/http/sender/http_client.c | 56 +++++++++++++---------------
 util/src/http_chunked_stream.c               | 28 +++++++++++++-
 2 files changed, 53 insertions(+), 31 deletions(-)


(axis-axis2-c-core) 02/02: Remove the unused prepend stream free function

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-c-core.git

commit 727677f2de45483db4fe723eb398e5607004fcae
Author: Robert Lazarski <ro...@gmail.com>
AuthorDate: Fri Aug 28 04:05:28 2026 -1000

    Remove the unused prepend stream free function
    
    It was superseded by the managed-stream convention the create function
    already follows: buffer_head holds the prepend buffer and fp the
    underlying stream, and axutil_stream_free's MANAGED case frees both
    plus the wrapper. This function frees the same three allocations
    through the extended fields that alias those handles, so wiring it up
    would have double-freed all of them. A note at the site records why
    there is no free function rather than leaving that to be rediscovered.
    
    Co-Authored-By: Claude Opus 5 (1M context) <no...@anthropic.com>
---
 src/core/transport/http/sender/http_client.c | 36 ++++++++++------------------
 1 file changed, 13 insertions(+), 23 deletions(-)

diff --git a/src/core/transport/http/sender/http_client.c b/src/core/transport/http/sender/http_client.c
index fa3b14cc7..6028f2473 100644
--- a/src/core/transport/http/sender/http_client.c
+++ b/src/core/transport/http/sender/http_client.c
@@ -190,29 +190,19 @@ axis2_prepend_stream_skip(
     return total_skipped;
 }
 
-static void AXIS2_CALL
-axis2_prepend_stream_free(
-    axutil_stream_t *stream,
-    const axutil_env_t *env)
-{
-    axis2_prepend_stream_impl_t *impl = (axis2_prepend_stream_impl_t *)stream;
-
-    if (impl)
-    {
-        if (impl->prepend_data)
-        {
-            AXIS2_FREE(env->allocator, impl->prepend_data);
-            impl->prepend_data = NULL;
-        }
-        /* Free the underlying stream */
-        if (impl->underlying)
-        {
-            axutil_stream_free(impl->underlying, env);
-            impl->underlying = NULL;
-        }
-        AXIS2_FREE(env->allocator, impl);
-    }
-}
+/*
+ * There is deliberately no free function for this stream type.
+ *
+ * The stream is AXIS2_STREAM_MANAGED and stores its cleanup handles in the
+ * base fields -- buffer_head for the prepend buffer, fp for the underlying
+ * stream -- which is the convention axutil_stream_free's MANAGED case exists
+ * to serve, prepend streams being the case it names. That path frees the
+ * buffer, the underlying stream and the wrapper.
+ *
+ * A free function here would free the same three allocations through the
+ * extended fields that alias those handles, so wiring one in would double-free
+ * all of them. Leave the cleanup where the create function put it.
+ */
 
 /*
  * Create a prepend stream wrapper that serves prepend_data first,


(axis-axis2-c-core) 01/02: Write the whole chunk the chunk header announced

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-c-core.git

commit e379cb7bf80dfdb655525375bfdcb176e51a7dd3
Author: Robert Lazarski <ro...@gmail.com>
AuthorDate: Fri Aug 28 03:40:11 2026 -1000

    Write the whole chunk the chunk header announced
    
    axutil_http_chunked_stream_write emitted a header naming count bytes
    and then wrote whatever one stream write accepted, which for a socket
    is whatever fits in its send buffer. Callers cannot recover from a
    short return there: two of the three respond by calling again with the
    entire buffer, so a second chunk header lands inside a chunk that was
    never finished, and it repeats while the writes keep coming up short.
    Complete the announced body or fail.
    
    Co-Authored-By: Claude Opus 5 (1M context) <no...@anthropic.com>
---
 src/core/transport/http/sender/http_client.c | 20 +++++++++++++-------
 util/src/http_chunked_stream.c               | 28 +++++++++++++++++++++++++++-
 2 files changed, 40 insertions(+), 8 deletions(-)

diff --git a/src/core/transport/http/sender/http_client.c b/src/core/transport/http/sender/http_client.c
index a9202a2a2..fa3b14cc7 100644
--- a/src/core/transport/http/sender/http_client.c
+++ b/src/core/transport/http/sender/http_client.c
@@ -770,20 +770,26 @@ axis2_http_client_send(
                 return AXIS2_FAILURE;
             }
 
-            while(written < client->req_body_size)
+            /* One call, not a loop. axutil_http_chunked_stream_write writes the
+             * whole body it was given or fails; looping on a short return used
+             * to re-send the body from the start under a fresh chunk header,
+             * which corrupts the framing rather than completing the write.
+             * Take the return in an int and test it before widening -- the -1
+             * is only distinguishable from a huge length while it is signed. */
             {
-                /* Take the return in an int and test it before widening: the
-                 * -1 is only distinguishable from a huge length while it is
-                 * still signed. */
                 int chunk_written = axutil_http_chunked_stream_write(chunked_stream, env,
                     client->req_body, client->req_body_size);
 
-                if(chunk_written < 0)
+                if(chunk_written < 0 || (size_t)chunk_written != client->req_body_size)
                 {
+                    AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
+                        "Failed to write the request body to the chunked stream");
                     status = AXIS2_FAILURE;
-                    break;
                 }
-                written = (size_t)chunk_written;
+                else
+                {
+                    written = (size_t)chunk_written;
+                }
             }
 
             if(AXIS2_SUCCESS == status)
diff --git a/util/src/http_chunked_stream.c b/util/src/http_chunked_stream.c
index ee37b6c22..06e101883 100644
--- a/util/src/http_chunked_stream.c
+++ b/util/src/http_chunked_stream.c
@@ -158,7 +158,33 @@ axutil_http_chunked_stream_write(
     }
     sprintf(tmp_buf, "%x%s", (unsigned int)count, AXIS2_HTTP_CRLF);
     axutil_stream_write(stream, env, tmp_buf, axutil_strlen(tmp_buf));
-    len = axutil_stream_write(stream, env, buffer, count);
+
+    /* The header above has already announced count bytes, so exactly count
+     * have to follow it or the framing is wrong for everything after this
+     * chunk. axutil_stream_write is under no obligation to take them all in
+     * one call -- a socket accepts what fits in its send buffer and reports
+     * the rest back -- so keep going until the announced body is complete.
+     *
+     * Returning a short count instead was worse than it looks: callers cannot
+     * recover from it. Two of them respond by calling again with the whole
+     * buffer, which emits a second chunk header in the middle of a chunk that
+     * was never finished, and repeats if the writes keep coming up short. */
+    {
+        size_t body_written = 0;
+
+        while(body_written < count)
+        {
+            len = axutil_stream_write(stream, env, (const axis2_char_t *)buffer + body_written,
+                count - body_written);
+            if(len <= 0)
+            {
+                return -1;
+            }
+            body_written += (size_t)len;
+        }
+        len = (int)body_written;
+    }
+
     axutil_stream_write(stream, env, AXIS2_HTTP_CRLF, 2);
     return len;
 }