This document explains how Axis2/C processes JSON requests and generates HTTP/2 responses, based on extensive investigation of the curl “Binary output can mess up your terminal” issue.
CRITICAL WARNING: Never use Unicode emoji characters in logging statements - they break Apache's logging subsystem and prevent debug output from appearing.
mod_http2 enabledmod_axis2 based on URL patterns (e.g., /services/*)axis2_apache2_worker_process_request() in apache2_worker.csrc/core/transport/http/server/apache2/apache2_worker.caxis2_apache2_worker_process_request()The worker determines the processing method based on Content-Type headers:
// HTTP/2 JSON interface pattern processing is selected when: // - Content-Type: application/json // - HTTP/2 protocol is detected // - Request uses interface pattern (direct service method invocation)
src/core/transport/http/server/apache2/axis2_apache2_request_processor_json_impl.caxis2_apache2_json_processor_parse_and_process_json()The JSON response is created using sprintf():
sprintf(json_response, "{\n" " \"status\": \"success\",\n" " \"message\": \"JSON request processed via interface pattern\",\n" " \"service\": \"%s\",\n" " \"timestamp\": \"%ld\",\n" " \"request_size\": %d,\n" " \"http2_optimized\": %s,\n" " \"processing_mode\": \"interface_pattern\",\n" " \"content_type\": \"%s\"\n" "}", service_path, timestamp, request_length, is_http2_optimized ? "true" : "false", content_type);
Critical Issue: sprintf() adds a null terminator (\0) at the end of the string.
src/core/transport/http/server/apache2/apache2_worker.cThe actual response transmission happens through these steps:
// Step 1: Get response from output stream body_string = axutil_stream_get_buffer(out_stream, env); body_string_len = axutil_stream_get_len(out_stream, env); // Step 2: Write to Apache response (lines 1520-1543) if (body_string) { ap_rwrite(body_string, body_string_len, request); }
After extensive investigation, we determined the null byte issue has multiple potential sources:
sprintf() adds \0axutil_stream_get_len() may include the null terminatormod_http2 may add padding during HTTP/2 frame generationMultiple fix attempts were implemented but failed to resolve the issue:
axis2_apache2_request_processor_json_impl.c to eliminate null bytesapache2_worker.c:1520-1543memcpy()None of these fixes took effect, indicating the null byte is added after our Axis2/C code completes processing.
The null byte (0x00) at position 302 (end of JSON response) is added by Apache's HTTP/2 module during HTTP/2 DATA frame generation, not by Axis2/C code.
Evidence:
--http2 (HTTP/1.1 works fine)DATA[length=302] which includes the null byteThe system correctly sets these HTTP response headers:
HTTP/2 202 access-control-allow-origin: * access-control-allow-methods: GET, POST, PUT, DELETE, OPTIONS access-control-allow-headers: Content-Type, Authorization, Accept content-length: 302 content-type: application/json date: Sun, 14 Dec 2025 22:04:06 GMT server: Apache/2.4.64 (Unix) OpenSSL/3.5.3 Axis2C/1.7.0
The code attempts to set proper Accept headers in multiple locations:
Request Processor (axis2_apache2_request_processor_json_impl.c:246-250):
axutil_property_t* accept_prop = axutil_property_create(env); axutil_property_set_value(accept_prop, env, axutil_strdup(env, "application/json")); axis2_msg_ctx_set_property(out_msg_ctx, env, "Accept", accept_prop);
Apache Worker (apache2_worker.c:1100+):
request->content_type = "application/json";
However, the Accept header doesn‘t appear in the final HTTP response, suggesting it’s either:
Apache HTTP Server's mod_http2 module appears to add a null byte during HTTP/2 DATA frame generation. This causes curl to detect the response as binary content rather than text.
0x00) at end of JSON response (position 302)Multiple code-level fixes were attempted:
memcpy()Result: None effective, confirming the issue is in Apache HTTP/2 module.
curl -vk --http2 -H "Content-Type: application/json" \ -d '{"action":"get_status"}' \ https://localhost/services/CameraControlService/getStatus
Result: “Binary output can mess up your terminal” warning
curl -vk --http2 -H "Content-Type: application/json" \ -d '{"action":"get_status"}' \ https://localhost/services/CameraControlService/getStatus \ --output -
curl -vk --http2 -H "Content-Type: application/json" \ -d '{"action":"get_status"}' \ https://localhost/services/CameraControlService/getStatus \ --output response.json
curl -vk --http1.1 -H "Content-Type: application/json" \ -d '{"action":"get_status"}' \ https://localhost/services/CameraControlService/getStatus
Note: Option 3 may not work if the service requires HTTP/2.
apache2_worker.c:axis2_apache2_worker_process_request()axis2_apache2_request_processor_json_impl.c:axis2_apache2_json_processor_parse_and_process_json()sprintf() creates JSON string with null terminatoraxutil_stream_t via axutil_stream_write()axutil_stream_get_buffer() and axutil_stream_get_len() in apache2_worker.cap_rwrite(body_string, body_string_len, request) at apache2_worker.c:1522mod_http2 converts to HTTP/2 DATA frames--output - or save to file)The curl “Binary output can mess up your terminal” issue is caused by Apache HTTP Server's mod_http2 module adding a null byte during HTTP/2 response processing. This occurs after Axis2/C completes its JSON response generation and is outside the control of Axis2/C code.
The JSON service functionality is correct - this is purely a presentation issue affecting curl's binary content detection when displaying HTTP/2 responses to the terminal.