Fix 1-byte buffer overwrites due to null-termination

Add axutil_stream_set_buffer_end_null function to allow memory
reallocation if needed when null-terminating a basic stream.

Fixes: AXIS2C-1600
diff --git a/axiom/src/om/om_data_source.c b/axiom/src/om/om_data_source.c
index 3959e49..4f6db77 100644
--- a/axiom/src/om/om_data_source.c
+++ b/axiom/src/om/om_data_source.c
@@ -108,16 +108,14 @@
 {
     int status = AXIS2_SUCCESS;
     axis2_char_t *data = NULL;
-    unsigned int data_len = 0;
 
     AXIS2_ENV_CHECK(env, AXIS2_FAILURE);
     AXIS2_PARAM_CHECK(env->error, om_output, AXIS2_FAILURE);
 
+    axutil_stream_set_buffer_end_null(data_source->stream, env);
     data = axutil_stream_get_buffer(data_source->stream, env);
-    data_len = axutil_stream_get_len(data_source->stream, env);
     if(data)
     {
-        data[data_len] = '\0';
         status = axiom_output_write(om_output, env, AXIOM_DATA_SOURCE, 1, data);
     }
     return status;
diff --git a/src/core/transport/http/common/simple_http_svr_conn.c b/src/core/transport/http/common/simple_http_svr_conn.c
index 958be28..4aa71e6 100644
--- a/src/core/transport/http/common/simple_http_svr_conn.c
+++ b/src/core/transport/http/common/simple_http_svr_conn.c
@@ -282,9 +282,9 @@
     if(response_stream)
     {
         body_size = axutil_stream_get_len(response_stream, env);
+        axutil_stream_set_buffer_end_null(response_stream, env);
         response_body = axutil_stream_get_buffer(response_stream, env);
         axutil_stream_flush_buffer(response_stream, env);
-        response_body[body_size] = AXIS2_ESC_NULL;
     }
 
     if(body_size <= 0 && !binary_content)
diff --git a/test/core/transport/http/test_http_transport.cc b/test/core/transport/http/test_http_transport.cc
index 86d1b2f..17ee4a0 100644
--- a/test/core/transport/http/test_http_transport.cc
+++ b/test/core/transport/http/test_http_transport.cc
@@ -32,6 +32,7 @@
 #include <axis2_json_writer.h>
 #include <axis2_json_reader.h>
 #endif
+#include <axis2_simple_http_svr_conn.h>
 
 #include "../../../cutest/include/cut_http_server.h"
 
@@ -450,3 +451,23 @@
 }
 #endif
 
+
+TEST_F(TestHTTPTransport, test_AXIS2C_1600)
+{
+    axis2_simple_http_svr_conn_t* conn = axis2_simple_http_svr_conn_create(
+            m_env, -1);
+
+    axis2_http_simple_response_t* resp = axis2_http_simple_response_create(
+            m_env, NULL, NULL, 0, NULL);
+    axis2_char_t body[AXIS2_STREAM_DEFAULT_BUF_SIZE+1];
+    memset(body, 'A', AXIS2_STREAM_DEFAULT_BUF_SIZE+1);
+    body[AXIS2_STREAM_DEFAULT_BUF_SIZE] = '\0';
+
+    axis2_http_simple_response_set_status_line(resp, m_env, "1.1", 200, "OK");
+    axis2_http_simple_response_set_body_string(resp, m_env, body);
+
+    axis2_simple_http_svr_conn_write_response(conn, m_env, resp);
+
+    axis2_http_simple_response_free(resp, m_env);
+    axis2_simple_http_svr_conn_free(conn, m_env);
+}
diff --git a/util/include/axutil_stream.h b/util/include/axutil_stream.h
index a506811..92c9c17 100644
--- a/util/include/axutil_stream.h
+++ b/util/include/axutil_stream.h
@@ -283,6 +283,16 @@
         const axutil_stream_t * stream,
         const axutil_env_t * env);
 
+    /**
+     * Appends a null terminator to the buffer, allocating additional memory
+     * if necessary.
+     * @return Length of the buffer plus null terminator, or -1 on error
+     */
+    AXIS2_EXTERN int AXIS2_CALL
+        axutil_stream_set_buffer_end_null(
+                axutil_stream_t *stream,
+                axutil_env_t *env);
+
     AXIS2_EXTERN axis2_status_t AXIS2_CALL
     axutil_stream_flush_buffer(
         axutil_stream_t * stream,
diff --git a/util/src/stream.c b/util/src/stream.c
index bdc4e03..8f3d986 100644
--- a/util/src/stream.c
+++ b/util/src/stream.c
@@ -377,6 +377,33 @@
     return stream->buffer;
 }
 
+AXIS2_EXTERN int AXIS2_CALL
+axutil_stream_set_buffer_end_null(
+    axutil_stream_t *stream,
+    axutil_env_t *env)
+{
+    if (!stream || !env) return -1;
+
+    if (stream->len + 1 >= stream->max_len) {
+
+        axis2_char_t *tmp = (axis2_char_t *)AXIS2_MALLOC(env->allocator,
+                sizeof(axis2_char_t) * (stream->len + 1));
+        if(!tmp)
+        {
+            AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
+            return -1;
+        }
+        stream->max_len = stream->len + 1;
+        memcpy(tmp, stream->buffer_head, sizeof(axis2_char_t) * stream->len);
+        AXIS2_FREE(env->allocator, stream->buffer_head);
+        stream->buffer = tmp;
+        stream->buffer_head = tmp;
+    }
+    *(stream->buffer_head + stream->len) = '\0';
+    return stream->len + 1;
+
+}
+
 AXIS2_EXTERN axis2_status_t AXIS2_CALL
 axutil_stream_flush_buffer(
     axutil_stream_t *stream,