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
The following commit(s) were added to refs/heads/master by this push:
new 3ee110729 fix http transport unit tests
3ee110729 is described below
commit 3ee110729a49c6e288c2fd27e327584099b1b1b8
Author: Robert Lazarski <[email protected]>
AuthorDate: Sat Jan 10 06:47:53 2026 -1000
fix http transport unit tests
---
docs/HTTP2_JSON_REQUEST_CODE_PATH.md | 207 +++++++++++++++++++++
include/axis2_msg_recv.h | 15 ++
src/core/engine/engine.c | 14 +-
src/core/receivers/msg_recv.c | 46 +++--
src/core/receivers/raw_xml_in_out_msg_recv.c | 21 +++
.../transport/http/util/http_transport_utils.c | 39 +++-
6 files changed, 320 insertions(+), 22 deletions(-)
diff --git a/docs/HTTP2_JSON_REQUEST_CODE_PATH.md
b/docs/HTTP2_JSON_REQUEST_CODE_PATH.md
index 8bf4b664d..2d2e935f2 100644
--- a/docs/HTTP2_JSON_REQUEST_CODE_PATH.md
+++ b/docs/HTTP2_JSON_REQUEST_CODE_PATH.md
@@ -865,3 +865,210 @@ With all fixes deployed, HTTP/2 JSON services achieve:
**Client Experience**: Clean, single JSON responses for all HTTP/2 requests
with zero issues.
This represents the **complete resolution** of all known HTTP/2 JSON
processing issues in Apache Axis2/C. The system now delivers enterprise-grade
HTTP/2 JSON web service functionality with reliability equivalent to
traditional HTTP/1.1 SOAP services.
+
+---
+
+## January 2026 Update: Conditional Compilation Regression Fix
+
+### Issue: HTTP/1.1 SOAP Tests Crashing After HTTP/2 JSON Changes
+
+**Date:** January 2026
+**Symptom:** SEGV crash in `raw_xml_in_out_msg_recv.c:209` during HTTP/1.1
SOAP tests
+**Root Cause:** Two separate issues introduced when adding HTTP/2 JSON support
+
+### Problem 1: Missing Conditional Compilation Guards
+
+The HTTP/2 JSON changes in `msg_recv.c` removed SOAP skeleton initialization
code **unconditionally** instead of using `#ifdef WITH_NGHTTP2` guards.
+
+**Original Code (Broken):**
+```c
+/* HTTP/2 Pure JSON Architecture - removed skeleton init */
+if(impl_class)
+{
+ /* Generic JSON service initialization - no SOAP skeleton needed */
+}
+```
+
+**Fixed Code:**
+```c
+if(impl_class)
+{
+#ifndef WITH_NGHTTP2
+ /* HTTP/1.1 SOAP mode - Full skeleton initialization */
+ axis2_svc_skeleton_t *skel = (axis2_svc_skeleton_t *)impl_class;
+ if (skel->ops && skel->ops->init)
+ {
+ skel->ops->init(skel, env);
+ }
+#else
+ /* HTTP/2 JSON mode - Generic initialization */
+#endif
+}
+```
+
+**Files Modified:**
+- `src/core/receivers/msg_recv.c` - Added `#ifndef WITH_NGHTTP2` guards in two
functions
+
+### Problem 2: Missing Function Declaration (ROOT CAUSE of Crash)
+
+The function `axis2_msg_recv_make_new_svc_obj` was **not declared** in any
header file. Without a declaration, C assumes it returns `int` (32-bit),
causing **pointer truncation** on 64-bit systems.
+
+**Symptom:** Compiler warning:
+```
+warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
+ 99 | svc_obj = (axis2_svc_skeleton_t
*)axis2_msg_recv_make_new_svc_obj(...);
+```
+
+**Impact:** 64-bit pointers truncated to 32-bit, causing invalid memory access
+
+**Fix Added to `include/axis2_msg_recv.h`:**
+```c
+/**
+ * Create or retrieve the service implementation object.
+ * HTTP/1.1 SOAP mode: Returns axis2_svc_skeleton_t* with full skeleton
initialization
+ * HTTP/2 JSON mode: Returns generic void* for JSON service implementation
+ */
+AXIS2_EXPORT void *AXIS2_CALL
+axis2_msg_recv_make_new_svc_obj(
+ axis2_msg_recv_t * msg_recv,
+ const axutil_env_t * env,
+ struct axis2_msg_ctx * msg_ctx);
+```
+
+### Problem 3: Safety Checks Added
+
+**File:** `src/core/receivers/raw_xml_in_out_msg_recv.c`
+
+Added defensive null checks before invoking service skeleton:
+
+```c
+if(status == AXIS2_SUCCESS)
+{
+ skel_invoked = AXIS2_TRUE;
+#ifndef WITH_NGHTTP2
+ /* HTTP/1.1 SOAP mode - Verify skeleton before invoke */
+ if(!svc_obj->ops)
+ {
+ AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
+ "Service skeleton ops is NULL - skeleton not properly
initialized");
+ status = AXIS2_FAILURE;
+ }
+ else if(!svc_obj->ops->invoke)
+ {
+ AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
+ "Service skeleton invoke function is NULL");
+ status = AXIS2_FAILURE;
+ }
+ else
+ {
+ result_node = svc_obj->ops->invoke(svc_obj, env, om_node, new_msg_ctx);
+ }
+#else
+ /* HTTP/2 JSON mode - Macro returns NULL safely */
+ result_node = AXIS2_SVC_SKELETON_INVOKE(svc_obj, env, om_node,
new_msg_ctx);
+#endif
+}
+```
+
+### Conditional Compilation Summary
+
+| File | Guard | HTTP/1.1 SOAP Behavior | HTTP/2 JSON Behavior |
+|------|-------|------------------------|----------------------|
+| `axis2_svc_skeleton.h` | `#ifndef WITH_NGHTTP2` | Full struct + macros |
typedef void + NULL macros |
+| `msg_recv.c` | `#ifndef WITH_NGHTTP2` | Skeleton init via ops->init() | No
initialization |
+| `raw_xml_in_out_msg_recv.c` | `#ifndef WITH_NGHTTP2` | Direct ops->invoke()
with safety checks | Macro returns NULL |
+
+### Build Mode Detection
+
+```bash
+# Check if HTTP/2 mode is enabled
+grep "WITH_NGHTTP2" config.h
+
+# If no match: HTTP/1.1 SOAP mode (full skeleton support)
+# If defined: HTTP/2 JSON mode (minimal skeleton compatibility)
+```
+
+### Testing After Fix
+
+```bash
+# HTTP/1.1 SOAP tests should pass
+make -C test/core/transport/http check
+
+# Expected result:
+# [==========] 8 tests from 1 test suite ran.
+# [ PASSED ] 8 tests.
+```
+
+### Key Lessons Learned
+
+1. **Always use conditional compilation** when modifying shared code for
HTTP/2 JSON support
+2. **Declare all public functions** in headers to prevent pointer truncation
on 64-bit
+3. **Add defensive null checks** before dereferencing function pointers
+4. **Build chain matters**: Changes to receivers require engine rebuild
+
+---
+
+## Memory Leak Fix: Service Provider Singleton Pattern
+
+### Problem Description
+
+AddressSanitizer detected a 72-byte memory leak originating from
`axis2_engine_service_provider_create`:
+
+```
+Direct leak of 72 byte(s) in 1 object(s) allocated from:
+ #1 axis2_engine_service_provider_create at
axis2_engine_service_provider.c:210
+ #2 axis2_engine_create at engine.c:71
+ #3 axis2_http_transport_utils_process_http_post_request at
http_transport_utils.c:899
+```
+
+### Root Cause
+
+The HTTP service provider was designed as a global singleton, but
`axis2_engine_create` was creating a new provider instance on EVERY engine
creation, overwriting the global and orphaning previous allocations:
+
+```c
+// ORIGINAL (LEAKY) CODE in engine.c:
+axis2_http_service_provider_t* service_provider =
axis2_engine_service_provider_create(env);
+if (service_provider) {
+ axis2_http_service_provider_set_impl(env, service_provider); //
Overwrites existing!
+}
+```
+
+In a multi-request server:
+1. Request 1: Engine creates provider A, sets global → A
+2. Request 2: Engine creates provider B, sets global → B (provider A orphaned
- LEAK!)
+3. Request 3: Engine creates provider C, sets global → C (provider B orphaned
- LEAK!)
+
+### Solution
+
+Modified `axis2_engine_create` to check for existing provider before creating:
+
+```c
+// FIXED CODE in engine.c:
+axis2_http_service_provider_t* existing_provider =
axis2_http_service_provider_get_impl(env);
+if (!existing_provider) {
+ axis2_http_service_provider_t* service_provider =
axis2_engine_service_provider_create(env);
+ if (service_provider) {
+ axis2_http_service_provider_set_impl(env, service_provider);
+ }
+}
+```
+
+### Files Modified
+
+| File | Change |
+|------|--------|
+| `src/core/engine/engine.c` | Check for existing provider before creating new
one |
+
+### Verification
+
+```bash
+# Run tests with AddressSanitizer
+make -C test/core/transport/http check
+
+# Expected: PASS with no memory leak reports
+```
+
+---
+
+**Document Updated:** January 2026
+**Status:** HTTP/1.1 SOAP + HTTP/2 JSON dual-mode support fully functional (no
memory leaks)
diff --git a/include/axis2_msg_recv.h b/include/axis2_msg_recv.h
index 92d28f6a0..e41682661 100644
--- a/include/axis2_msg_recv.h
+++ b/include/axis2_msg_recv.h
@@ -165,6 +165,21 @@ extern "C"
axis2_msg_recv_t * msg_recv,
const axutil_env_t * env);
+ /**
+ * Create or retrieve the service implementation object.
+ * HTTP/1.1 SOAP mode: Returns axis2_svc_skeleton_t* with full skeleton
initialization
+ * HTTP/2 JSON mode: Returns generic void* for JSON service implementation
+ * @param msg_recv pointer to message receiver
+ * @param env pointer to environment struct
+ * @param msg_ctx pointer to message context
+ * @return pointer to service implementation object, or NULL on failure
+ */
+ AXIS2_EXPORT void *AXIS2_CALL
+ axis2_msg_recv_make_new_svc_obj(
+ axis2_msg_recv_t * msg_recv,
+ const axutil_env_t * env,
+ struct axis2_msg_ctx * msg_ctx);
+
/**
* Delete the service skeleton object created by make_new_svc_obj
* @param msg_recv pointer to message receiver
diff --git a/src/core/engine/engine.c b/src/core/engine/engine.c
index 5bf912a34..34bf310b8 100644
--- a/src/core/engine/engine.c
+++ b/src/core/engine/engine.c
@@ -66,11 +66,15 @@ axis2_engine_create(
engine->conf_ctx = conf_ctx;
}
- /* Register HTTP service provider implementation to eliminate circular
dependency */
+ /* Register HTTP service provider implementation to eliminate circular
dependency.
+ * Only create if not already set (true singleton pattern). */
{
- axis2_http_service_provider_t* service_provider =
axis2_engine_service_provider_create(env);
- if (service_provider) {
- axis2_http_service_provider_set_impl(env, service_provider);
+ axis2_http_service_provider_t* existing_provider =
axis2_http_service_provider_get_impl(env);
+ if (!existing_provider) {
+ axis2_http_service_provider_t* service_provider =
axis2_engine_service_provider_create(env);
+ if (service_provider) {
+ axis2_http_service_provider_set_impl(env, service_provider);
+ }
}
}
@@ -82,7 +86,7 @@ axis2_engine_free(
axis2_engine_t * engine,
const axutil_env_t * env)
{
- /* REVOLUTIONARY: Clean up HTTP service provider */
+ /* Clean up HTTP service provider singleton */
axis2_http_service_provider_t* service_provider =
axis2_http_service_provider_get_impl(env);
if (service_provider) {
service_provider->free(service_provider, env);
diff --git a/src/core/receivers/msg_recv.c b/src/core/receivers/msg_recv.c
index f6d9dba13..c64ab7eb2 100644
--- a/src/core/receivers/msg_recv.c
+++ b/src/core/receivers/msg_recv.c
@@ -25,6 +25,9 @@
#include <axiom_soap_envelope.h>
#include <axiom_soap_body.h>
#include <axutil_thread.h>
+#ifndef WITH_NGHTTP2
+#include <axis2_svc_skeleton.h>
+#endif
struct axis2_msg_recv
{
@@ -137,16 +140,20 @@ axis2_msg_recv_load_and_init_svc_impl(
impl_class = axutil_class_loader_create_dll(env, impl_info_param);
AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "loading the services from
msg_recv_load_and_init_svc");
- /* HTTP/2 Pure JSON Architecture - Generic JSON service initialization
- * Replaced SOAP skeleton initialization with generic approach
- * as SOAP skeletons are incompatible with HTTP/2 JSON-only design
- */
if(impl_class)
{
- /* Generic JSON service initialization - no SOAP skeleton operations
needed */
- axis2_conf_t *conf = NULL;
- conf = axis2_conf_ctx_get_conf(msg_recv->conf_ctx, env);
- /* JSON services initialized generically without skeleton-specific
operations */
+#ifndef WITH_NGHTTP2
+ /* HTTP/1.1 SOAP mode - Full skeleton initialization */
+ axis2_svc_skeleton_t *skel = (axis2_svc_skeleton_t *)impl_class;
+ if (skel->ops && skel->ops->init)
+ {
+ skel->ops->init(skel, env);
+ }
+#else
+ /* HTTP/2 JSON mode - Generic JSON service initialization
+ * SOAP skeletons are incompatible with HTTP/2 JSON-only design
+ */
+#endif
}
axis2_svc_set_impl_class(svc, env, impl_class);
@@ -199,9 +206,10 @@ axis2_msg_recv_free(
return;
}
-/* HTTP/2 Pure JSON Architecture - Generic JSON service object creation
- * Replaced SOAP skeleton pattern with generic JSON service implementation
- * as SOAP skeletons are incompatible with HTTP/2 JSON-only design
+/*
+ * Create or retrieve service implementation object.
+ * HTTP/1.1 SOAP mode: Returns axis2_svc_skeleton_t* with full skeleton
initialization
+ * HTTP/2 JSON mode: Returns generic void* for JSON service implementation
*/
AXIS2_EXPORT void *AXIS2_CALL
axis2_msg_recv_make_new_svc_obj(
@@ -257,12 +265,20 @@ axis2_msg_recv_make_new_svc_obj(
impl_class = axutil_class_loader_create_dll(env, impl_info_param);
- /* HTTP/2 Pure JSON Architecture - Generic initialization for JSON
services
- * Replaced SOAP skeleton init with generic approach
- */
if(impl_class)
{
- /* Generic JSON service initialization - no SOAP skeleton needed */
+#ifndef WITH_NGHTTP2
+ /* HTTP/1.1 SOAP mode - Initialize service skeleton */
+ axis2_svc_skeleton_t *skel = (axis2_svc_skeleton_t *)impl_class;
+ if (skel->ops && skel->ops->init)
+ {
+ skel->ops->init(skel, env);
+ }
+#else
+ /* HTTP/2 JSON mode - Generic JSON service initialization
+ * SOAP skeletons are incompatible with HTTP/2 JSON-only design
+ */
+#endif
}
axis2_svc_set_impl_class(svc, env, impl_class);
diff --git a/src/core/receivers/raw_xml_in_out_msg_recv.c
b/src/core/receivers/raw_xml_in_out_msg_recv.c
index 6acbca1f0..63a8b8cba 100644
--- a/src/core/receivers/raw_xml_in_out_msg_recv.c
+++ b/src/core/receivers/raw_xml_in_out_msg_recv.c
@@ -206,7 +206,28 @@ axis2_raw_xml_in_out_msg_recv_invoke_business_logic_sync(
if(status == AXIS2_SUCCESS)
{
skel_invoked = AXIS2_TRUE;
+#ifndef WITH_NGHTTP2
+ /* HTTP/1.1 SOAP mode - Verify skeleton is properly initialized
before invoke */
+ if(!svc_obj->ops)
+ {
+ AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
+ "Service skeleton ops is NULL - skeleton not properly
initialized");
+ status = AXIS2_FAILURE;
+ }
+ else if(!svc_obj->ops->invoke)
+ {
+ AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
+ "Service skeleton invoke function is NULL");
+ status = AXIS2_FAILURE;
+ }
+ else
+ {
+ result_node = svc_obj->ops->invoke(svc_obj, env, om_node,
new_msg_ctx);
+ }
+#else
+ /* HTTP/2 JSON mode - Use macro (returns NULL for JSON services) */
result_node = AXIS2_SVC_SKELETON_INVOKE(svc_obj, env, om_node,
new_msg_ctx);
+#endif
}
if(result_node)
diff --git a/src/core/transport/http/util/http_transport_utils.c
b/src/core/transport/http/util/http_transport_utils.c
index 977de8331..db2bf689f 100644
--- a/src/core/transport/http/util/http_transport_utils.c
+++ b/src/core/transport/http/util/http_transport_utils.c
@@ -899,12 +899,24 @@ axis2_http_transport_utils_process_http_post_request(
engine = axis2_engine_create(env, conf_ctx);
if(!soap_envelope)
+ {
+ if(engine)
+ {
+ axis2_engine_free(engine, env);
+ }
return AXIS2_FAILURE;
+ }
soap_body = axiom_soap_envelope_get_body(soap_envelope, env);
if(!soap_body)
+ {
+ if(engine)
+ {
+ axis2_engine_free(engine, env);
+ }
return AXIS2_FAILURE;
+ }
if(!is_svc_callback)
{
@@ -1392,14 +1404,26 @@ axis2_http_transport_utils_process_http_put_request(
engine = axis2_engine_create(env, conf_ctx);
if(!soap_envelope)
+ {
+ if(engine)
+ {
+ axis2_engine_free(engine, env);
+ }
return AXIS2_FAILURE;
+ }
soap_body = axiom_soap_envelope_get_body(soap_envelope, env);
if(!soap_body)
+ {
+ if(engine)
+ {
+ axis2_engine_free(engine, env);
+ }
return AXIS2_FAILURE;
+ }
- is_client_property = axis2_msg_ctx_get_property(msg_ctx, env,
+ is_client_property = axis2_msg_ctx_get_property(msg_ctx, env,
AXIS2_TRANPORT_IS_APPLICATION_CLIENT_SIDE);
if(is_client_property)
{
@@ -1531,6 +1555,10 @@ axis2_http_transport_utils_process_http_head_request(
axis2_msg_ctx_set_soap_envelope(msg_ctx, env, soap_envelope);
engine = axis2_engine_create(env, conf_ctx);
axis2_engine_receive(engine, env, msg_ctx);
+ if(engine)
+ {
+ axis2_engine_free(engine, env);
+ }
return AXIS2_TRUE;
}
@@ -1601,6 +1629,10 @@ axis2_http_transport_utils_process_http_get_request(
engine = axis2_engine_create(env, conf_ctx);
axis2_engine_receive(engine, env, msg_ctx);
+ if(engine)
+ {
+ axis2_engine_free(engine, env);
+ }
return AXIS2_TRUE;
}
@@ -1670,9 +1702,12 @@ axis2_http_transport_utils_process_http_delete_request(
}
axis2_msg_ctx_set_soap_envelope(msg_ctx, env, soap_envelope);
-
engine = axis2_engine_create(env, conf_ctx);
axis2_engine_receive(engine, env, msg_ctx);
+ if(engine)
+ {
+ axis2_engine_free(engine, env);
+ }
return AXIS2_TRUE;
}