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:11 UTC
(axis-axis2-c-core) 01/02: Write the whole chunk the chunk header announced
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;
}