/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <axis2_http_transport_utils.h>
#include <string.h>
#include <ctype.h>
#include <axis2_conf.h>
#include <axis2_op.h>
#include <axutil_qname.h>
#include <axis2_http_transport.h>
#include <axiom_soap_builder.h>
#include <axiom_soap_envelope.h>
#include <axis2_engine.h>
#include <axiom_soap_body.h>
#include <axutil_utils.h>
#include <axiom_namespace.h>
#include <axiom_node.h>
#include <axutil_hash.h>
#include <axiom_soap_const.h>
#include <axis2_http_header.h>
#include <axutil_property.h>
#include <axutil_utils.h>
#include <axiom_mime_parser.h>
#include <axis2_http_accept_record.h>
#include <axis2_disp.h>
#include <axis2_msg.h>
#include <axutil_string_util.h>
#include <stdlib.h>
#include <axutil_uuid_gen.h>
#include <platforms/axutil_platform_auto_sense.h>
#include <axiom_mime_part.h>
#include <axutil_class_loader.h>

#ifdef AXIS2_JSON_ENABLED
#include <axis2_json_reader.h>
#endif

/* REVOLUTIONARY: Service provider interface for architectural decoupling */
#include <axis2_http_service_provider.h>

#define AXIOM_MIME_BOUNDARY_BYTE 45

/** Size of the buffer to be used when reading a file */
#ifndef AXIS2_FILE_READ_SIZE
#define AXIS2_FILE_READ_SIZE 2048
#endif

/** Content length value to be used in case of chunked content  */
#ifndef AXIS2_CHUNKED_CONTENT_LENGTH
#define AXIS2_CHUNKED_CONTENT_LENGTH 100000000
#endif

/* Make static to avoid ODR violations when linked into multiple shared libraries.
 * Making the variable static means each shared library gets its own private copy. */
static const axis2_char_t *AXIS2_TRANS_UTIL_DEFAULT_CHAR_ENCODING =
    AXIS2_HTTP_HEADER_DEFAULT_CHAR_ENCODING;

/***************************** Function headers *******************************/

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_http_transport_utils_process_http_post_request(
    const axutil_env_t * env,
    axis2_msg_ctx_t * msg_ctx,
    axutil_stream_t * in_stream,
    axutil_stream_t * out_stream,
    const axis2_char_t * content_type,
    const size_t content_length,
    axutil_string_t * soap_action_header,
    const axis2_char_t * request_uri);

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_http_transport_utils_process_http_put_request(
    const axutil_env_t * env,
    axis2_msg_ctx_t * msg_ctx,
    axutil_stream_t * in_stream,
    axutil_stream_t * out_stream,
    const axis2_char_t * content_type,
    const size_t content_length,
    axutil_string_t * soap_action_header,
    const axis2_char_t * request_uri);

AXIS2_EXTERN axis2_bool_t AXIS2_CALL
axis2_http_transport_utils_process_http_get_request(
    const axutil_env_t * env,
    axis2_msg_ctx_t * msg_ctx,
    axutil_stream_t * in_stream,
    axutil_stream_t * out_stream,
    const axis2_char_t * content_type,
    axutil_string_t * soap_action_header,
    const axis2_char_t * request_uri,
    axis2_conf_ctx_t * conf_ctx,
    axutil_hash_t * request_params);

AXIS2_EXTERN axis2_bool_t AXIS2_CALL
axis2_http_transport_utils_process_http_head_request(
    const axutil_env_t * env,
    axis2_msg_ctx_t * msg_ctx,
    axutil_stream_t * in_stream,
    axutil_stream_t * out_stream,
    const axis2_char_t * content_type,
    axutil_string_t * soap_action_header,
    const axis2_char_t * request_uri,
    axis2_conf_ctx_t * conf_ctx,
    axutil_hash_t * request_params);

AXIS2_EXTERN axis2_bool_t AXIS2_CALL
axis2_http_transport_utils_process_http_delete_request(
    const axutil_env_t * env,
    axis2_msg_ctx_t * msg_ctx,
    axutil_stream_t * in_stream,
    axutil_stream_t * out_stream,
    const axis2_char_t * content_type,
    axutil_string_t * soap_action_header,
    const axis2_char_t * request_uri,
    axis2_conf_ctx_t * conf_ctx,
    axutil_hash_t * request_params);

AXIS2_EXTERN axiom_stax_builder_t *AXIS2_CALL
axis2_http_transport_utils_select_builder_for_mime(
    const axutil_env_t * env,
    axis2_char_t * request_uri,
    axis2_msg_ctx_t * msg_ctx,
    axutil_stream_t * in_stream,
    axis2_char_t * content_type);

AXIS2_EXTERN axis2_bool_t AXIS2_CALL
axis2_http_transport_utils_is_optimized(
    const axutil_env_t * env,
    axiom_element_t * om_element);

AXIS2_EXTERN axis2_bool_t AXIS2_CALL
axis2_http_transport_utils_do_write_mtom(
    const axutil_env_t * env,
    axis2_msg_ctx_t * msg_ctx);

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_http_transport_utils_strdecode(
    const axutil_env_t * env,
    axis2_char_t * dest,
    axis2_char_t * src);

AXIS2_EXTERN int AXIS2_CALL
axis2_http_transport_utils_hexit(
    axis2_char_t c);

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_services_html(
    const axutil_env_t * env,
    axis2_conf_ctx_t * conf_ctx);

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_services_static_wsdl(
    const axutil_env_t * env,
    axis2_conf_ctx_t * conf_ctx,
    axis2_char_t * request_url);

AXIS2_EXTERN axutil_string_t *AXIS2_CALL
axis2_http_transport_utils_get_charset_enc(
    const axutil_env_t * env,
    const axis2_char_t * content_type);

int AXIS2_CALL
axis2_http_transport_utils_on_data_request(
    char *buffer,
    int size,  /* Must be int to match AXIS2_READ_INPUT_CALLBACK signature */
    void *ctx);

AXIS2_EXTERN axiom_soap_envelope_t *AXIS2_CALL
axis2_http_transport_utils_create_soap_msg(
    const axutil_env_t * env,
    axis2_msg_ctx_t * msg_ctx,
    const axis2_char_t * soap_ns_uri);

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_value_from_content_type(
    const axutil_env_t * env,
    const axis2_char_t * content_type,
    const axis2_char_t * key);

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_http_transport_utils_dispatch_and_verify(
    const axutil_env_t * env,
    axis2_msg_ctx_t * msg_ctx);

AXIS2_EXTERN axiom_soap_envelope_t *AXIS2_CALL
axis2_http_transport_utils_handle_media_type_url_encoded(
    const axutil_env_t * env,
    axis2_msg_ctx_t * msg_ctx,
    axutil_hash_t * param_map,
    axis2_char_t * method);

AXIS2_EXTERN void AXIS2_CALL
axis2_http_transport_utils_session_map_free_void_arg(
    void *sm_void,
    const axutil_env_t *env);

static axis2_status_t
axis2_http_transport_utils_send_attachment_using_file(
    const axutil_env_t * env,
    axutil_http_chunked_stream_t *chunked_stream,
    FILE *fp,
    axis2_byte_t *buffer,
    size_t buffer_size);

static axis2_status_t
axis2_http_transport_utils_send_attachment_using_callback(
    const axutil_env_t * env,
    axutil_http_chunked_stream_t *chunked_stream,
    axiom_mtom_sending_callback_t *callback,
    void *handler,
    void *user_param);

static axis2_char_t *
axis2_http_transport_utils_copy_key(
        const axutil_env_t *env, 
        axis2_char_t *);
    
static axis2_char_t *
axis2_http_transport_utils_copy_value(
        const axutil_env_t *env, 
        axis2_char_t *pair);

static void 
axis2_http_transport_utils_parse_session_str(
        const axutil_env_t *env, 
        axis2_char_t *str, 
        axutil_hash_t *ht);
/***************************** End of function headers ************************/

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_http_transport_utils_transport_out_init(
    axis2_http_transport_out_t *response,
    const axutil_env_t *env)
{
    response->http_status_code_name = NULL;
    response->http_status_code = 0;
    response->msg_ctx = NULL;
    response->response_data = NULL;
    response->content_type = NULL;
    response->response_data_length = 0;
    response->content_language = NULL;
    response->output_headers = NULL;
    return AXIS2_SUCCESS;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_http_transport_utils_transport_out_uninit(
    axis2_http_transport_out_t *response,
    const axutil_env_t *env)
{
    if(response->msg_ctx)
    {
        axis2_msg_ctx_free(response->msg_ctx, env);
    }
    return AXIS2_SUCCESS;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_http_transport_utils_transport_in_init(
    axis2_http_transport_in_t *request,
    const axutil_env_t *env)
{
    request->content_type = NULL;
    request->content_length = 0;
    request->msg_ctx = NULL;
    request->soap_action = NULL;
    request->request_uri = NULL;
    request->in_stream = NULL;
    request->remote_ip = NULL;
    request->svr_port = NULL;
    request->transfer_encoding = NULL;
    request->accept_header = NULL;
    request->accept_language_header = NULL;
    request->accept_charset_header = NULL;
    request->request_method = 0;
    request->out_transport_info = NULL;
    request->request_url_prefix = NULL;
    return AXIS2_SUCCESS;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_http_transport_utils_transport_in_uninit(
    axis2_http_transport_in_t *request,
    const axutil_env_t *env)
{
    if(request->msg_ctx)
    {
        axis2_msg_ctx_reset_out_transport_info(request->msg_ctx, env);
        axis2_msg_ctx_free(request->msg_ctx, env);
    }
    return AXIS2_SUCCESS;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_http_transport_utils_process_http_post_request(
    const axutil_env_t * env,
    axis2_msg_ctx_t * msg_ctx,
    axutil_stream_t * in_stream,
    axutil_stream_t * out_stream,
    const axis2_char_t * content_type,
    const size_t content_length,
    axutil_string_t * soap_action_header,
    const axis2_char_t * request_uri)
{
    /* DEFENSIVE: Validate critical parameters before any processing */
    if (!env || !env->log)
    {
        return AXIS2_FAILURE;
    }

    AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
        "[HTTP_TRANSPORT_UTILS] ENTRY POINT - Processing HTTP POST request");

    /* DEFENSIVE: Validate msg_ctx - crash protection */
    if (!msg_ctx)
    {
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
            "[HTTP_TRANSPORT_UTILS] CRITICAL ERROR - msg_ctx is NULL, cannot process request");
        return AXIS2_FAILURE;
    }

    AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
        "[HTTP_TRANSPORT_UTILS] Parameters - content_type: %s, request_uri: %s, msg_ctx: %p",
        content_type ? content_type : "NULL",
        request_uri ? request_uri : "NULL",
        (void*)msg_ctx);
    axiom_soap_envelope_t *soap_envelope = NULL;
    axiom_soap_builder_t *soap_builder = NULL;
    axiom_stax_builder_t *om_builder = NULL;
    axis2_bool_t is_soap11 = AXIS2_FALSE;
    axiom_xml_reader_t *xml_reader = NULL;
    axutil_string_t *char_set_str = NULL;

    axis2_conf_ctx_t *conf_ctx = NULL;
    axis2_callback_info_t *callback_ctx = NULL;
    axis2_callback_info_t *mime_cb_ctx = NULL;
    axutil_hash_t *headers = NULL;
    axis2_engine_t *engine = NULL;
    axiom_soap_body_t *soap_body = NULL;
    axis2_status_t status = AXIS2_FAILURE;
    axutil_hash_t *binary_data_map = NULL;
    axis2_char_t *soap_body_str = NULL;
    axutil_stream_t *stream = NULL;
    axis2_bool_t do_rest = AXIS2_FALSE;
    axis2_bool_t run_as_get = AXIS2_FALSE;
    axis2_char_t *soap_action = NULL;
    unsigned int soap_action_len = 0;
    axutil_property_t *http_error_property = NULL;
    axiom_mime_parser_t *mime_parser = NULL;
    axis2_bool_t is_svc_callback = AXIS2_FALSE;
    axutil_property_t *is_client_property = NULL;
    axis2_bool_t is_application_client_side = AXIS2_FALSE;
    axis2_char_t *mime_boundary = NULL;
    axis2_bool_t check_for_fault = AXIS2_FALSE;
    axis2_bool_t has_fault = AXIS2_FALSE;
	axis2_char_t *encoding_header_value = NULL;

    AXIS2_PARAM_CHECK(env->error, msg_ctx, AXIS2_FAILURE);
    AXIS2_PARAM_CHECK(env->error, in_stream, AXIS2_FAILURE);
    AXIS2_PARAM_CHECK(env->error, out_stream, AXIS2_FAILURE);
    AXIS2_PARAM_CHECK(env->error, content_type, AXIS2_FAILURE);
    AXIS2_PARAM_CHECK(env->error, request_uri, AXIS2_FAILURE);


    conf_ctx = axis2_msg_ctx_get_conf_ctx(msg_ctx, env);

    callback_ctx = AXIS2_MALLOC(env->allocator, sizeof(axis2_callback_info_t));
    /* Note: the memory created above is freed in xml reader free function
     as this is passed on to the reader */
    callback_ctx->in_stream = in_stream;
    callback_ctx->env = env;
    callback_ctx->content_length = content_length;
    callback_ctx->unread_len = content_length;
    callback_ctx->chunked_stream = NULL;

    soap_action = (axis2_char_t *)axutil_string_get_buffer(soap_action_header, env);
    soap_action_len = axutil_string_get_length(soap_action_header, env);

    if(soap_action && (soap_action_len > 0))
    {
        /* remove leading and trailing " s */
        if(AXIS2_DOUBLE_QUOTE == soap_action[0])
        {
            memmove(soap_action, soap_action + sizeof(char), soap_action_len - 1 + sizeof(char));
        }
        if(AXIS2_DOUBLE_QUOTE == soap_action[soap_action_len - 2])
        {
            soap_action[soap_action_len - 2] = AXIS2_ESC_NULL;
        }
    }
    else
    {
        /** soap action is null, check whether soap action is in content_type header */
        soap_action = axis2_http_transport_utils_get_value_from_content_type(env, content_type,
            AXIS2_ACTION);
    }

	headers = axis2_msg_ctx_get_transport_headers(msg_ctx, env);

	encoding_header_value = axis2_msg_ctx_get_transfer_encoding(msg_ctx, env);

    if(encoding_header_value && axutil_strstr(encoding_header_value, AXIS2_HTTP_HEADER_TRANSFER_ENCODING_CHUNKED))
    {
        /* In case Transfer encoding is set to message context, some streams strip chunking meta
         data, so chunked streams should not be created */

        callback_ctx->content_length = -1;
        callback_ctx->unread_len = -1;
        AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[chunked ] setting length to -1");
    }else if(headers)
    {
        axis2_http_header_t *encoding_header = NULL;
        encoding_header = (axis2_http_header_t *)axutil_hash_get(headers,
            AXIS2_HTTP_HEADER_TRANSFER_ENCODING, AXIS2_HASH_KEY_STRING);

        if(encoding_header)
        {
            axis2_char_t *encoding_value = NULL;
            encoding_value = axis2_http_header_get_value(encoding_header, env);
            if(encoding_value && 0 == axutil_strcasecmp(encoding_value,
                AXIS2_HTTP_HEADER_TRANSFER_ENCODING_CHUNKED))
            {
                callback_ctx->chunked_stream = axutil_http_chunked_stream_create(env, in_stream);

                if(!callback_ctx->chunked_stream)
                {
                    AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Error occurred in"
                        " creating in chunked stream.");
                    return AXIS2_FAILURE;
                }

                AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "HTTP"
                    " stream chunked");
            }
        }
    }/*
    else
    {
        
        axis2_char_t *value = axis2_msg_ctx_get_transfer_encoding(msg_ctx, env);

        if(value && axutil_strstr(value, AXIS2_HTTP_HEADER_TRANSFER_ENCODING_CHUNKED))
        {
            // In case Transfer encoding is set to message context, some streams strip chunking meta
            // data, so chunked streams should not be created 

            callback_ctx->content_length = -1;
            callback_ctx->unread_len = -1;
            AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[chunked ] setting length to -1");
        }
    }*/

    /* when the message contains does not contain pure XML we can't send it 
     * directly to the parser, First we need to separate the SOAP part from
     * the attachment */

    if(strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_MULTIPART_RELATED))
    {
        /* get mime boundary */
        mime_boundary = axis2_http_transport_utils_get_value_from_content_type(env,
            content_type, AXIS2_HTTP_HEADER_CONTENT_TYPE_MIME_BOUNDARY);

        if(mime_boundary)
        {
            /*axiom_mime_parser_t *mime_parser = NULL;*/
            size_t soap_body_len = 0;
            axutil_param_t *buffer_size_param = NULL;
            axutil_param_t *max_buffers_param = NULL;
            axutil_param_t *attachment_dir_param = NULL;
            axutil_param_t *callback_name_param = NULL;
            axutil_param_t *enable_service_callback_param = NULL;
            axis2_char_t *value_size = NULL;
            axis2_char_t *value_num = NULL;
            axis2_char_t *value_dir = NULL;
            axis2_char_t *value_callback = NULL;
            axis2_char_t *value_enable_service_callback = NULL;
            size_t size = 0;
            int num = 0;  /* num is count, not size */

            mime_parser = axiom_mime_parser_create(env);
            /* This is the size of the buffer we keep inside mime_parser
             * when parsing. */

            enable_service_callback_param = axis2_msg_ctx_get_parameter(msg_ctx, env,
                AXIS2_ENABLE_MTOM_SERVICE_CALLBACK);
            if(enable_service_callback_param)
            {
                value_enable_service_callback = (axis2_char_t *)axutil_param_get_value(
                    enable_service_callback_param, env);
                if(value_enable_service_callback)
                {
                    if(!axutil_strcmp(value_enable_service_callback, AXIS2_VALUE_TRUE))
                    {
                        is_svc_callback = AXIS2_TRUE;
                    }
                }
            }

            buffer_size_param = axis2_msg_ctx_get_parameter(msg_ctx, env, AXIS2_MTOM_BUFFER_SIZE);
            if(buffer_size_param)
            {
                value_size = (axis2_char_t *)axutil_param_get_value(buffer_size_param, env);
                if(value_size)
                {
                    size = atoi(value_size);
                    axiom_mime_parser_set_buffer_size(mime_parser, env, size);
                }
            }

            /* We create an array of buffers in order to conatin SOAP data inside
             * mime_parser. This is the number of sucj buffers */
            max_buffers_param = axis2_msg_ctx_get_parameter(msg_ctx, env, AXIS2_MTOM_MAX_BUFFERS);
            if(max_buffers_param)
            {
                value_num = (axis2_char_t *)axutil_param_get_value(max_buffers_param, env);
                if(value_num)
                {
                    num = atoi(value_num);
                    axiom_mime_parser_set_max_buffers(mime_parser, env, num);
                }
            }
            /* If this paramter is there mime_parser will cached the attachment 
             * using to the directory for large attachments. */

            callback_name_param = axis2_msg_ctx_get_parameter(msg_ctx, env,
                AXIS2_MTOM_CACHING_CALLBACK);
            if(callback_name_param)
            {
                value_callback = (axis2_char_t *)axutil_param_get_value(callback_name_param, env);
                if(value_callback)
                {
                    axiom_mime_parser_set_caching_callback_name(mime_parser, env, value_callback);
                }
            }

            attachment_dir_param = axis2_msg_ctx_get_parameter(msg_ctx, env, AXIS2_ATTACHMENT_DIR);

            if(attachment_dir_param)
            {
                value_dir = (axis2_char_t *)axutil_param_get_value(attachment_dir_param, env);
                if(value_dir)
                {
                    axiom_mime_parser_set_attachment_dir(mime_parser, env, value_dir);
                }
            }

            axiom_mime_parser_set_mime_boundary(mime_parser, env, mime_boundary);

            if(axiom_mime_parser_parse_for_soap(mime_parser, env,
                axis2_http_transport_utils_on_data_request, (void *)callback_ctx, mime_boundary)
                == AXIS2_FAILURE)
            {
                return AXIS2_FAILURE;
            }

            if(!is_svc_callback)
            {
                binary_data_map = axiom_mime_parser_parse_for_attachments(mime_parser, env,
                    axis2_http_transport_utils_on_data_request, (void *)callback_ctx,
                    mime_boundary, NULL);
                if(!binary_data_map)
                {
                    return AXIS2_FAILURE;
                }
            }
            soap_body_len = (int)axiom_mime_parser_get_soap_body_len(mime_parser, env);
            soap_body_str = axiom_mime_parser_get_soap_body_str(mime_parser, env);

            if(!is_svc_callback)
            {
                if(callback_ctx->chunked_stream)
                {
                    axutil_http_chunked_stream_free(callback_ctx->chunked_stream, env);
                    callback_ctx->chunked_stream = NULL;
                }
            }
            else
            {
                mime_cb_ctx = AXIS2_MALLOC(env->allocator, sizeof(axis2_callback_info_t));
                if(mime_cb_ctx)
                {
                    mime_cb_ctx->in_stream = callback_ctx->in_stream;
                    mime_cb_ctx->env = callback_ctx->env;
                    mime_cb_ctx->content_length = callback_ctx->content_length;
                    mime_cb_ctx->unread_len = callback_ctx->unread_len;
                    mime_cb_ctx->chunked_stream = callback_ctx->chunked_stream;
                }
            }

            stream = axutil_stream_create_basic(env);
            if(stream)
            {
                axutil_stream_write(stream, env, soap_body_str, soap_body_len);
                callback_ctx->in_stream = stream;
                callback_ctx->chunked_stream = NULL;
                callback_ctx->content_length = soap_body_len;
                callback_ctx->unread_len = soap_body_len;
            }
            /*axiom_mime_parser_free(mime_parser, env);
             mime_parser = NULL;*/

            /*AXIS2_FREE(env->allocator, mime_boundary);*/
        }
        /*AXIS2_FREE(env->allocator, mime_boundary);*/
    }

    if(soap_action_header)
    {
        axis2_msg_ctx_set_soap_action(msg_ctx, env, soap_action_header);

    }
    else if(soap_action)
    {
        axutil_string_t *soap_action_str = NULL;
        soap_action_str = axutil_string_create(env, soap_action);
        axis2_msg_ctx_set_soap_action(msg_ctx, env, soap_action_str);
        axutil_string_free(soap_action_str, env);
    }
    axis2_msg_ctx_set_to(msg_ctx, env, axis2_endpoint_ref_create(env, request_uri));

    axis2_msg_ctx_set_server_side(msg_ctx, env, AXIS2_TRUE);

    char_set_str = axis2_http_transport_utils_get_charset_enc(env, content_type);

    axis2_msg_ctx_set_charset_encoding(msg_ctx, env, char_set_str);

    /* Check if we're processing JSON content */
#ifdef AXIS2_JSON_ENABLED
    if (content_type && strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_JSON))
    {
        axis2_json_reader_t* json_reader = NULL;
        axiom_soap_body_t* soap_body = NULL;

        /* DEFENSIVE: Double-check msg_ctx before property access */
        if (!msg_ctx)
        {
            return AXIS2_FAILURE;
        }

        /* Check if JSON data is already available from the JSON processor */
        axutil_property_t* json_body_prop = NULL;
        json_body_prop = axis2_msg_ctx_get_property(msg_ctx, env, "JSON_REQUEST_BODY");

        if (json_body_prop) {

            /* Use pre-processed JSON data instead of reading from stream */
            axis2_char_t* json_body = (axis2_char_t*)axutil_property_get_value(json_body_prop, env);
            if (json_body) {
                AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
                    "[HTTP_TRANSPORT_UTILS] JSON PROCESSING - Using pre-processed JSON: %.100s...", json_body);
            }
        } else {
            AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
                "[HTTP_TRANSPORT_UTILS] JSON PROCESSING - No pre-processed JSON found, attempting stream read");

            /* Try to read from stream but with timeout protection */
            json_reader = axis2_json_reader_create_for_stream(env, in_stream);
            if (!json_reader)
            {
                AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
                    "[HTTP_TRANSPORT_UTILS] JSON PROCESSING - FAILED to create JSON reader (invalid JSON syntax)");

                /* Set JSON parse error flag in message context for proper error response */
                axutil_property_t* json_error_prop = axutil_property_create(env);
                if (json_error_prop)
                {
                    axutil_property_set_value(json_error_prop, env,
                        axutil_strdup(env, "Invalid JSON syntax in request body"));
                    axis2_msg_ctx_set_property(msg_ctx, env, "JSON_PARSE_ERROR", json_error_prop);
                }

                /* Return failure to trigger proper error handling */
                AXIS2_ERROR_SET(env->error, AXIS2_ERROR_INVALID_STATE_PARAM, AXIS2_FAILURE);
                return AXIS2_FAILURE;
            } else {
                AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
                    "[HTTP_TRANSPORT_UTILS] JSON PROCESSING - Parsing JSON content from stream");
                status = axis2_json_reader_read(json_reader, env);
                if (status != AXIS2_SUCCESS)
                {
                    AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
                        "[HTTP_TRANSPORT_UTILS] JSON PROCESSING - JSON parsing FAILED, continuing anyway");
                }

                /* Clean up reader */
                axis2_json_reader_free(json_reader, env);
            }
        }

        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
            "[HTTP_TRANSPORT_UTILS] JSON PROCESSING - Completed JSON processing, continuing to SOAP envelope creation");

        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
            "[HTTP_TRANSPORT_UTILS] JSON PROCESSING - Creating minimal SOAP envelope for JSON request");

        /* Create a minimal SOAP envelope for JSON requests */
        soap_envelope = axiom_soap_envelope_create_default_soap_envelope(env, AXIOM_SOAP12);
        if (soap_envelope) {
            AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
                "[HTTP_TRANSPORT_UTILS] JSON PROCESSING - SOAP envelope created successfully for JSON processing");
        } else {
            AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
                "[HTTP_TRANSPORT_UTILS] JSON PROCESSING - FAILED to create SOAP envelope");
            return AXIS2_FAILURE;
        }
    }
    else
    {
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
            "[HTTP_TRANSPORT_UTILS] NON-JSON BRANCH - Content-type '%s' does not contain JSON - processing as XML",
            content_type ? content_type : "NULL");
#else
    AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
        "[HTTP_TRANSPORT_UTILS] JSON disabled - AXIS2_JSON_ENABLED not defined, processing as XML");
#endif
    xml_reader = axiom_xml_reader_create_for_io(env, axis2_http_transport_utils_on_data_request,
        NULL, (void *)callback_ctx, axutil_string_get_buffer(char_set_str, env));

    if(!xml_reader)
    {
        return AXIS2_FAILURE;
    }

    om_builder = axiom_stax_builder_create(env, xml_reader);
    if(!om_builder)
    {
        axiom_xml_reader_free(xml_reader, env);
        xml_reader = NULL;
        return AXIS2_FAILURE;
    }

    if(strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_APPL_SOAP))
    {
        is_soap11 = AXIS2_FALSE;
        soap_builder = axiom_soap_builder_create(env, om_builder,
            AXIOM_SOAP12_SOAP_ENVELOPE_NAMESPACE_URI);
        if(!soap_builder)
        {
            /* We should not be freeing om_builder here as it is done by
             axiom_soap_builder_create in case of error - Samisa */
            om_builder = NULL;
            xml_reader = NULL;
            axis2_msg_ctx_set_is_soap_11(msg_ctx, env, is_soap11);
            return AXIS2_FAILURE;
        }

        soap_envelope = axiom_soap_builder_get_soap_envelope(soap_builder, env);
        if(!soap_envelope)
        {
            axiom_stax_builder_free(om_builder, env);
            om_builder = NULL;
            xml_reader = NULL;
            axiom_soap_builder_free(soap_builder, env);
            soap_builder = NULL;
            axis2_msg_ctx_set_is_soap_11(msg_ctx, env, is_soap11);
            return AXIS2_FAILURE;
        }
    }
    else if(strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_TEXT_XML))
    {
        is_soap11 = AXIS2_TRUE;
        if(soap_action_header)
        {
            soap_builder = axiom_soap_builder_create(env, om_builder,
                AXIOM_SOAP11_SOAP_ENVELOPE_NAMESPACE_URI);
            if(!soap_builder)
            {
                /* We should not be freeing om_builder here as it is done by
                 axiom_soap_builder_create in case of error - Samisa */
                om_builder = NULL;
                xml_reader = NULL;
                axis2_msg_ctx_set_is_soap_11(msg_ctx, env, is_soap11);
                return AXIS2_FAILURE;
            }
            soap_envelope = axiom_soap_builder_get_soap_envelope(soap_builder, env);
            if(!soap_envelope)
            {
                axiom_soap_builder_free(soap_builder, env);
                om_builder = NULL;
                xml_reader = NULL;
                soap_builder = NULL;
                axis2_msg_ctx_set_is_soap_11(msg_ctx, env, is_soap11);
                return AXIS2_FAILURE;
            }
        }
        else
        {
            /* REST support */
            do_rest = AXIS2_TRUE;
        }
    }

    else if(strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_X_WWW_FORM_URLENCODED))
    {
        /* REST support */
        do_rest = AXIS2_TRUE;
        run_as_get = AXIS2_TRUE;
    }
    else
    {
        http_error_property = axutil_property_create(env);
        axutil_property_set_value(http_error_property, env, AXIS2_HTTP_UNSUPPORTED_MEDIA_TYPE);
        axis2_msg_ctx_set_property(msg_ctx, env, AXIS2_HTTP_TRANSPORT_ERROR, http_error_property);
    }

    if(soap_builder)
    {
        if(mime_parser)
        {
            axiom_soap_builder_set_mime_parser(soap_builder, env, mime_parser);
            if(mime_cb_ctx)
            {
                axiom_soap_builder_set_callback_ctx(soap_builder, env, mime_cb_ctx);
                axiom_soap_builder_set_callback_function(soap_builder, env,
                    axis2_http_transport_utils_on_data_request);
            }
            else if(is_svc_callback)
            {
                return AXIS2_FAILURE;
            }
        }
    }
#ifdef AXIS2_JSON_ENABLED
    }
#endif

    if(do_rest)
    {
        /* REST support */
        axutil_param_t *rest_param = axis2_msg_ctx_get_parameter(msg_ctx, env, AXIS2_ENABLE_REST);
        if(rest_param && 0 == axutil_strcmp(AXIS2_VALUE_TRUE, axutil_param_get_value(rest_param,
            env)))
        {
            axis2_msg_ctx_set_doing_rest(msg_ctx, env, AXIS2_TRUE);
            axis2_msg_ctx_set_rest_http_method(msg_ctx, env, AXIS2_HTTP_POST);
            axis2_msg_ctx_set_soap_envelope(msg_ctx, env, soap_envelope);
        }
        else
        {
            return AXIS2_FAILURE;
        }
        if(AXIS2_SUCCESS != axis2_http_transport_utils_dispatch_and_verify(env, msg_ctx))
        {
            return AXIS2_FAILURE;
        }
    }

    if(run_as_get)
    {
        axis2_char_t *buffer = NULL;
        axis2_char_t *new_url = NULL;
        buffer = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * (content_length + 1));
        if(!buffer)
        {
            return AXIS2_FAILURE;
        }
        /* AXIS2C-1495: Pass content_length + 1 because on_data_request subtracts 1
         * to reserve space for null terminator. Without this, last char is truncated. */
        axis2_http_transport_utils_on_data_request(buffer, content_length + 1, (void *)callback_ctx);

        new_url = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * ((int)(strlen(request_uri)
            + strlen(buffer)) + 2));
        if(!new_url)
        {
            return AXIS2_FAILURE;
        }
        sprintf(new_url, "%s?%s", request_uri, buffer);
        AXIS2_FREE(env->allocator, buffer);

        soap_envelope = axis2_http_transport_utils_handle_media_type_url_encoded(env, msg_ctx,
            axis2_http_transport_utils_get_request_params(env, new_url), AXIS2_HTTP_POST);
    }

    if(binary_data_map)
    {
        axiom_soap_builder_set_mime_body_parts(soap_builder, env, binary_data_map);
    }

    axis2_msg_ctx_set_soap_envelope(msg_ctx, env, soap_envelope);

    /* Defensive: validate conf_ctx before engine creation */
    if (!conf_ctx)
    {
        return AXIS2_FAILURE;
    }

    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)
    {
        is_client_property = axis2_msg_ctx_get_property(msg_ctx, env, 
                AXIS2_TRANPORT_IS_APPLICATION_CLIENT_SIDE);
        if(is_client_property)
        {
            axis2_char_t *prop_value = NULL;
            prop_value = axutil_property_get_value(is_client_property, env);
            if(prop_value && !axutil_strcmp(prop_value , AXIS2_VALUE_TRUE))
            {
                is_application_client_side = AXIS2_TRUE;
            }
        }
        if(mime_boundary || is_application_client_side)
        {
            check_for_fault = AXIS2_TRUE;
        }
        if(check_for_fault)
        {
            has_fault = axiom_soap_body_has_fault(soap_body, env);
        }
        if(has_fault)
        {
            status = axis2_engine_receive_fault(engine, env, msg_ctx);
        }
        else
        {
#ifdef WITH_NGHTTP2
            /* HTTP/2 JSON Error Handling - Check for JSON processing flag */
            axutil_property_t *http2_error_prop = axis2_msg_ctx_get_property(msg_ctx, env, "HTTP2_JSON_ERROR_HANDLING");
            if (http2_error_prop) {
                /* Clear any existing errors before processing */
                env->error->error_number = AXIS2_ERROR_NONE;

                status = axis2_engine_receive(engine, env, msg_ctx);

                /* Check for processing errors and convert to JSON response */
                if (status != AXIS2_SUCCESS || env->error->error_number != AXIS2_ERROR_NONE) {
                    AXIS2_LOG_INFO(env->log, "HTTP/2 JSON processing error detected - converting to JSON response");

                    /* Create JSON error response directly */
                    axiom_soap_envelope_t *error_envelope = axiom_soap_envelope_create_default_soap_envelope(env, AXIOM_SOAP12);
                    axiom_soap_body_t *error_body = axiom_soap_envelope_get_body(error_envelope, env);

                    /* Create JSON error node instead of SOAP fault */
                    axiom_node_t *error_node = axiom_node_create(env);
                    axiom_element_t *error_element = axiom_element_create(env, error_node, "jsonError", NULL, NULL);
                    axiom_element_set_text(error_element, env,
                        "{"
                        "\"error\":\"HTTP/2 JSON Processing Error\","
                        "\"message\":\"Request processed but encountered processing error\","
                        "\"status\":\"error\","
                        "\"transport\":\"HTTP/2\","
                        "\"content_type\":\"application/json\""
                        "}", error_node);

                    axiom_soap_body_add_child(error_body, env, error_node);
                    axis2_msg_ctx_set_soap_envelope(msg_ctx, env, error_envelope);

                    /* Set JSON content type for response */
                    axutil_property_t *content_type_prop = axutil_property_create(env);
                    axutil_property_set_value(content_type_prop, env, "application/json");
                    axis2_msg_ctx_set_property(msg_ctx, env, AXIS2_HTTP_HEADER_CONTENT_TYPE, content_type_prop);

                    AXIS2_LOG_INFO(env->log, "HTTP/2 JSON error response created successfully");
                    status = AXIS2_SUCCESS; /* Mark as success since we handled the error */
                }
            } else {
                status = axis2_engine_receive(engine, env, msg_ctx);
            }
#else
            status = axis2_engine_receive(engine, env, msg_ctx);
#endif
        }
    }
    else
    {
        status = axis2_engine_receive(engine, env, msg_ctx);
    }

    if(!axis2_msg_ctx_get_soap_envelope(msg_ctx, env) && AXIS2_FALSE == is_soap11)
    {
        axiom_soap_envelope_t *def_envelope = axiom_soap_envelope_create_default_soap_envelope(env,
            AXIOM_SOAP12);
        axis2_msg_ctx_set_soap_envelope(msg_ctx, env, def_envelope);
    }

    if(engine)
    {
        axis2_engine_free(engine, env);
    }

    if(soap_body_str)
    {
        AXIS2_FREE(env->allocator, soap_body_str);
    }

    if(stream)
    {
        axutil_stream_free(stream, env);
    }

    if(char_set_str)
    {
        axutil_string_free(char_set_str, env);
    }
    if(!soap_builder && om_builder)
    {
        axiom_stax_builder_free_self(om_builder, env);
        om_builder = NULL;
    }
    if(!axutil_string_get_buffer(soap_action_header, env) && soap_action)
    {
        AXIS2_FREE(env->allocator, soap_action);
        soap_action = NULL;
    }
    return status;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_http_transport_utils_process_http_put_request(
    const axutil_env_t * env,
    axis2_msg_ctx_t * msg_ctx,
    axutil_stream_t * in_stream,
    axutil_stream_t * out_stream,
    const axis2_char_t * content_type,
    const size_t content_length,
    axutil_string_t * soap_action_header,
    const axis2_char_t * request_uri)
{
    axiom_soap_envelope_t *soap_envelope = NULL;
    axiom_soap_builder_t *soap_builder = NULL;
    axiom_stax_builder_t *om_builder = NULL;
    axis2_bool_t is_soap11 = AXIS2_FALSE;
    axiom_xml_reader_t *xml_reader = NULL;
    axutil_string_t *char_set_str = NULL;

    axis2_conf_ctx_t *conf_ctx = NULL;
    axis2_callback_info_t *callback_ctx;
    axutil_hash_t *headers = NULL;
    axis2_engine_t *engine = NULL;
    axiom_soap_body_t *soap_body = NULL;
    axis2_status_t status = AXIS2_FAILURE;
    axutil_hash_t *binary_data_map = NULL;
    axis2_char_t *soap_body_str = NULL;
    axutil_stream_t *stream = NULL;
    axis2_bool_t do_rest = AXIS2_FALSE;
    axis2_bool_t run_as_get = AXIS2_FALSE;
    axutil_property_t *http_error_property = NULL;
    axutil_property_t *is_client_property = NULL;
    axis2_bool_t is_application_client_side = AXIS2_FALSE;
    axis2_char_t *mime_boundary = NULL;
    axis2_bool_t check_for_fault = AXIS2_FALSE;
    axis2_bool_t has_fault = AXIS2_FALSE;

    AXIS2_PARAM_CHECK(env->error, msg_ctx, AXIS2_FAILURE);
    AXIS2_PARAM_CHECK(env->error, in_stream, AXIS2_FAILURE);
    AXIS2_PARAM_CHECK(env->error, out_stream, AXIS2_FAILURE);
    AXIS2_PARAM_CHECK(env->error, content_type, AXIS2_FAILURE);
    AXIS2_PARAM_CHECK(env->error, request_uri, AXIS2_FAILURE);

    conf_ctx = axis2_msg_ctx_get_conf_ctx(msg_ctx, env);

    callback_ctx = AXIS2_MALLOC(env->allocator, sizeof(axis2_callback_info_t));
    /* Note: the memory created above is freed in xml reader free function
     as this is passed on to the reader */
    callback_ctx->in_stream = in_stream;
    callback_ctx->env = env;
    callback_ctx->content_length = content_length;
    callback_ctx->unread_len = content_length;
    callback_ctx->chunked_stream = NULL;

    headers = axis2_msg_ctx_get_transport_headers(msg_ctx, env);
    if(headers)
    {
        axis2_http_header_t *encoding_header = NULL;
        encoding_header = (axis2_http_header_t *)axutil_hash_get(headers,
            AXIS2_HTTP_HEADER_TRANSFER_ENCODING, AXIS2_HASH_KEY_STRING);

        if(encoding_header)
        {
            axis2_char_t *encoding_value = NULL;
            encoding_value = axis2_http_header_get_value(encoding_header, env);
            if(encoding_value && 0 == axutil_strcasecmp(encoding_value,
                AXIS2_HTTP_HEADER_TRANSFER_ENCODING_CHUNKED))
            {
                callback_ctx->chunked_stream = axutil_http_chunked_stream_create(env, in_stream);
                if(!callback_ctx->chunked_stream)
                {
                    AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Error occured in"
                        " creating in chunked stream.");
                    return AXIS2_FAILURE;
                }
                AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "HTTP"
                    " stream chunked");
            }
        }
    }
    else
    {
        /* check content encoding from msg ctx property */
        axis2_char_t *value = axis2_msg_ctx_get_transfer_encoding(msg_ctx, env);

        if(value && axutil_strstr(value, AXIS2_HTTP_HEADER_TRANSFER_ENCODING_CHUNKED))
        {
            /* this is an UGLY hack to get some of the transports working 
             e.g. PHP transport where it strips the chunking info in case of chunking
             and also gives out a content lenght of 0.
             We need to fix the transport design to fix sutuations like this.
             */
            callback_ctx->content_length = AXIS2_CHUNKED_CONTENT_LENGTH;
            callback_ctx->unread_len = callback_ctx->content_length;
        }
    }

    if(strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_MULTIPART_RELATED))
    {
        /* get mime boundry */
        mime_boundary = axis2_http_transport_utils_get_value_from_content_type(env,
            content_type, AXIS2_HTTP_HEADER_CONTENT_TYPE_MIME_BOUNDARY);

        if(mime_boundary)
        {
            axiom_mime_parser_t *mime_parser = NULL;
            size_t soap_body_len = 0;
            axutil_param_t *buffer_size_param = NULL;
            axutil_param_t *max_buffers_param = NULL;
            axutil_param_t *attachment_dir_param = NULL;
            axutil_param_t *callback_name_param = NULL;
            axis2_char_t *value_size = NULL;
            axis2_char_t *value_num = NULL;
            axis2_char_t *value_dir = NULL;
            axis2_char_t *value_callback = NULL;
            size_t size = 0;
            int num = 0;  /* num is count, not size */

            mime_parser = axiom_mime_parser_create(env);

            buffer_size_param = axis2_msg_ctx_get_parameter(msg_ctx, env, AXIS2_MTOM_BUFFER_SIZE);
            if(buffer_size_param)
            {
                value_size = (axis2_char_t *)axutil_param_get_value(buffer_size_param, env);
                if(value_size)
                {
                    size = atoi(value_size);
                    axiom_mime_parser_set_buffer_size(mime_parser, env, size);
                }
            }

            max_buffers_param = axis2_msg_ctx_get_parameter(msg_ctx, env, AXIS2_MTOM_MAX_BUFFERS);
            if(max_buffers_param)
            {
                value_num = (axis2_char_t *)axutil_param_get_value(max_buffers_param, env);
                if(value_num)
                {
                    num = atoi(value_num);
                    axiom_mime_parser_set_max_buffers(mime_parser, env, num);
                }
            }

            callback_name_param = axis2_msg_ctx_get_parameter(msg_ctx, env,
                AXIS2_MTOM_CACHING_CALLBACK);
            if(callback_name_param)
            {
                value_callback = (axis2_char_t *)axutil_param_get_value(callback_name_param, env);
                if(value_callback)
                {
                    axiom_mime_parser_set_caching_callback_name(mime_parser, env, value_callback);
                }
            }

            attachment_dir_param = axis2_msg_ctx_get_parameter(msg_ctx, env, AXIS2_ATTACHMENT_DIR);

            if(attachment_dir_param)
            {
                value_dir = (axis2_char_t *)axutil_param_get_value(attachment_dir_param, env);
                if(value_dir)
                {
                    axiom_mime_parser_set_attachment_dir(mime_parser, env, value_dir);
                }
            }

            if(mime_parser)
            {
                /*binary_data_map = 
                 axiom_mime_parser_parse(mime_parser, env,
                 axis2_http_transport_utils_on_data_request,
                 (void *) callback_ctx,
                 mime_boundary);*/
                if(!binary_data_map)
                {
                    return AXIS2_FAILURE;
                }
                soap_body_len = (int)axiom_mime_parser_get_soap_body_len(mime_parser, env);
                soap_body_str = axiom_mime_parser_get_soap_body_str(mime_parser, env);
            }

            stream = axutil_stream_create_basic(env);
            if(stream)
            {
                axutil_stream_write(stream, env, soap_body_str, soap_body_len);
                callback_ctx->in_stream = stream;
                callback_ctx->chunked_stream = NULL;
                callback_ctx->content_length = soap_body_len;
                callback_ctx->unread_len = soap_body_len;
            }
            axiom_mime_parser_free(mime_parser, env);
            mime_parser = NULL;
        }
        /*AXIS2_FREE(env->allocator, mime_boundary);*/
    }

    axis2_msg_ctx_set_to(msg_ctx, env, axis2_endpoint_ref_create(env, request_uri));

    axis2_msg_ctx_set_server_side(msg_ctx, env, AXIS2_TRUE);

    char_set_str = axis2_http_transport_utils_get_charset_enc(env, content_type);

#ifdef AXIS2_JSON_ENABLED
    if (content_type && strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_JSON))
    {
        axis2_json_reader_t* json_reader = NULL;
        axiom_soap_body_t* soap_body = NULL;
        /* HTTP/2 Pure JSON Architecture - JSON data handle instead of axiom node */

        json_reader = axis2_json_reader_create_for_stream(env, in_stream);
        if (!json_reader)
        {
            return AXIS2_FAILURE;
        }

        status = axis2_json_reader_read(json_reader, env);
        if (status != AXIS2_SUCCESS)
        {
            axis2_json_reader_free(json_reader, env);
            return status;
        }

        /* HTTP/2 Pure JSON Architecture - Get JSON data directly, no axiom conversion */
        void* json_data = axis2_json_reader_get_root_node(json_reader, env);
        if (!json_data)
        {
            axis2_json_reader_free(json_reader, env);
            return AXIS2_FAILURE;
        }

        axis2_json_reader_free(json_reader, env);

        /* HTTP/2 Pure JSON Architecture - Skip SOAP envelope creation for JSON processing */
        /* No SOAP envelope needed for pure JSON processing - HTTP/2 JSON services handle requests directly */
    }
    else
    {
#endif

    xml_reader = axiom_xml_reader_create_for_io(env, axis2_http_transport_utils_on_data_request,
        NULL, (void *)callback_ctx, axutil_string_get_buffer(char_set_str, env));

    if(!xml_reader)
    {
        return AXIS2_FAILURE;
    }

    axis2_msg_ctx_set_charset_encoding(msg_ctx, env, char_set_str);

    om_builder = axiom_stax_builder_create(env, xml_reader);
    if(!om_builder)
    {
        axiom_xml_reader_free(xml_reader, env);
        xml_reader = NULL;
        return AXIS2_FAILURE;
    }

    if(strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_APPL_SOAP))
    {
        is_soap11 = AXIS2_FALSE;
        soap_builder = axiom_soap_builder_create(env, om_builder,
            AXIOM_SOAP12_SOAP_ENVELOPE_NAMESPACE_URI);
        if(!soap_builder)
        {
            /* We should not be freeing om_builder here as it is done by
             axiom_soap_builder_create in case of error - Samisa */
            om_builder = NULL;
            xml_reader = NULL;
            axis2_msg_ctx_set_is_soap_11(msg_ctx, env, is_soap11);
            return AXIS2_FAILURE;
        }

        soap_envelope = axiom_soap_builder_get_soap_envelope(soap_builder, env);
        if(!soap_envelope)
        {
            axiom_stax_builder_free(om_builder, env);
            om_builder = NULL;
            xml_reader = NULL;
            axiom_soap_builder_free(soap_builder, env);
            soap_builder = NULL;
            axis2_msg_ctx_set_is_soap_11(msg_ctx, env, is_soap11);
            return AXIS2_FAILURE;
        }
    }
    else if(strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_TEXT_XML))
    {
        do_rest = AXIS2_TRUE;
        if(soap_action_header)
        {
            return AXIS2_FAILURE;
        }
        else
        {
            /* REST support */
            do_rest = AXIS2_TRUE;
        }
    }
    else if(strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_X_WWW_FORM_URLENCODED))
    {
        /* REST support */
        do_rest = AXIS2_TRUE;
        run_as_get = AXIS2_TRUE;
    }
    else
    {
        http_error_property = axutil_property_create(env);
        axutil_property_set_value(http_error_property, env, AXIS2_HTTP_UNSUPPORTED_MEDIA_TYPE);
        axis2_msg_ctx_set_property(msg_ctx, env, AXIS2_HTTP_TRANSPORT_ERROR, http_error_property);
    }

    if(do_rest)
    {
        /* REST support */
        axutil_param_t *rest_param = axis2_msg_ctx_get_parameter(msg_ctx, env, AXIS2_ENABLE_REST);
        if(rest_param && 0 == axutil_strcmp(AXIS2_VALUE_TRUE, axutil_param_get_value(rest_param,
            env)))
        {
            /* HTTP/2 Pure JSON Architecture - SOAP envelope creation removed for JSON processing */
            axis2_msg_ctx_set_doing_rest(msg_ctx, env, AXIS2_TRUE);
            axis2_msg_ctx_set_rest_http_method(msg_ctx, env, AXIS2_HTTP_PUT);
            axis2_msg_ctx_set_soap_envelope(msg_ctx, env, soap_envelope);
        }
        else
        {
            return AXIS2_FAILURE;
        }
        if(AXIS2_SUCCESS != axis2_http_transport_utils_dispatch_and_verify(env, msg_ctx))
        {
            return AXIS2_FAILURE;
        }
    }
#ifdef AXIS2_JSON_ENABLED
    }
#endif

    if(run_as_get)
    {
        axis2_char_t *buffer = NULL;
        axis2_char_t *new_url = NULL;
        buffer = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * (content_length + 1));
        if(!buffer)
        {
            return AXIS2_FAILURE;
        }
        /* AXIS2C-1495: Pass content_length + 1 because on_data_request subtracts 1
         * to reserve space for null terminator. Without this, last char is truncated. */
        axis2_http_transport_utils_on_data_request(buffer, content_length + 1, (void *)callback_ctx);

        new_url = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * ((int)(strlen(request_uri)
            + strlen(buffer)) + 2));
        if(!new_url)
        {
            return AXIS2_FAILURE;
        }
        sprintf(new_url, "%s?%s", request_uri, buffer);
        AXIS2_FREE(env->allocator, buffer);

        soap_envelope = axis2_http_transport_utils_handle_media_type_url_encoded(env, msg_ctx,
            axis2_http_transport_utils_get_request_params(env, new_url), AXIS2_HTTP_POST);
    }

    if(binary_data_map)
    {
        axiom_soap_builder_set_mime_body_parts(soap_builder, env, binary_data_map);
    }

    axis2_msg_ctx_set_soap_envelope(msg_ctx, env, soap_envelope);

    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,
            AXIS2_TRANPORT_IS_APPLICATION_CLIENT_SIDE);
    if(is_client_property)
    {
        axis2_char_t *prop_value = NULL;
        prop_value = axutil_property_get_value(is_client_property, env);
        if(prop_value && !axutil_strcmp(prop_value , AXIS2_VALUE_TRUE))
        {
            is_application_client_side = AXIS2_TRUE;
        }
    }
    if(mime_boundary || is_application_client_side)
    {
        check_for_fault = AXIS2_TRUE;
    }
    if(check_for_fault)
    {
        has_fault = axiom_soap_body_has_fault(soap_body, env);
    }
    if(has_fault)
    {
        status = axis2_engine_receive_fault(engine, env, msg_ctx);
    }
    else
    {
        status = axis2_engine_receive(engine, env, msg_ctx);
    }
    if(mime_boundary)
    {
        AXIS2_FREE(env->allocator, mime_boundary);
    }
    if(!axis2_msg_ctx_get_soap_envelope(msg_ctx, env) && AXIS2_FALSE == is_soap11)
    {
        axiom_soap_envelope_t *def_envelope = axiom_soap_envelope_create_default_soap_envelope(env,
            AXIOM_SOAP12);
        axis2_msg_ctx_set_soap_envelope(msg_ctx, env, def_envelope);
    }

    if(engine)
    {
        axis2_engine_free(engine, env);
    }

    if(soap_body_str)
    {
        AXIS2_FREE(env->allocator, soap_body_str);
    }

    if(stream)
    {
        axutil_stream_free(stream, env);
    }

    if(char_set_str)
    {
        axutil_string_free(char_set_str, env);
    }
    if(!soap_builder && om_builder)
    {
        axiom_stax_builder_free_self(om_builder, env);
        om_builder = NULL;
    }
    return status;
}

AXIS2_EXTERN axis2_bool_t AXIS2_CALL
axis2_http_transport_utils_process_http_head_request(
    const axutil_env_t * env,
    axis2_msg_ctx_t * msg_ctx,
    axutil_stream_t * in_stream,
    axutil_stream_t * out_stream,
    const axis2_char_t * content_type,
    axutil_string_t * soap_action_header,
    const axis2_char_t * request_uri,
    axis2_conf_ctx_t * conf_ctx,
    axutil_hash_t * request_params)
{
    axiom_soap_envelope_t *soap_envelope = NULL;
    axis2_engine_t *engine = NULL;
    axis2_bool_t do_rest = AXIS2_TRUE;

    AXIS2_PARAM_CHECK(env->error, msg_ctx, AXIS2_FALSE);
    AXIS2_PARAM_CHECK(env->error, in_stream, AXIS2_FALSE);
    AXIS2_PARAM_CHECK(env->error, out_stream, AXIS2_FALSE);

    AXIS2_PARAM_CHECK(env->error, request_uri, AXIS2_FALSE);

    axis2_msg_ctx_set_to(msg_ctx, env, axis2_endpoint_ref_create(env, request_uri));
    axis2_msg_ctx_set_server_side(msg_ctx, env, AXIS2_TRUE);

#ifdef AXIS2_JSON_ENABLED
    if (content_type && strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_JSON))
    {
        /* axis2_msg_ctx_set_doing_json(msg_ctx, env, AXIS2_TRUE); */
    }
    else
#endif
    if(content_type && strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_TEXT_XML))
    {
        if(soap_action_header)
        {
            do_rest = AXIS2_FALSE;
        }
    }
    else if(content_type && strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_APPL_SOAP))
    {
        do_rest = AXIS2_FALSE;
    }

    if(do_rest)
    {
        axis2_msg_ctx_set_doing_rest(msg_ctx, env, AXIS2_TRUE);
        axis2_msg_ctx_set_rest_http_method(msg_ctx, env, AXIS2_HTTP_HEAD);
    }
    else
    {
        axis2_msg_ctx_set_doing_rest(msg_ctx, env, AXIS2_FALSE);
    }
    if(AXIS2_SUCCESS != axis2_http_transport_utils_dispatch_and_verify(env, msg_ctx))
    {
        return AXIS2_FALSE;
    }

    soap_envelope = axis2_http_transport_utils_handle_media_type_url_encoded(env, msg_ctx,
        request_params, AXIS2_HTTP_HEAD);
    if(!soap_envelope)
    {
        return AXIS2_FALSE;
    }
    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;
}

AXIS2_EXTERN axis2_bool_t AXIS2_CALL
axis2_http_transport_utils_process_http_get_request(
    const axutil_env_t * env,
    axis2_msg_ctx_t * msg_ctx,
    axutil_stream_t * in_stream,
    axutil_stream_t * out_stream,
    const axis2_char_t * content_type,
    axutil_string_t * soap_action_header,
    const axis2_char_t * request_uri,
    axis2_conf_ctx_t * conf_ctx,
    axutil_hash_t * request_params)
{
    axiom_soap_envelope_t *soap_envelope = NULL;
    axis2_engine_t *engine = NULL;
    axis2_bool_t do_rest = AXIS2_TRUE;

    AXIS2_PARAM_CHECK(env->error, msg_ctx, AXIS2_FALSE);
    AXIS2_PARAM_CHECK(env->error, in_stream, AXIS2_FALSE);
    AXIS2_PARAM_CHECK(env->error, out_stream, AXIS2_FALSE);
    AXIS2_PARAM_CHECK(env->error, request_uri, AXIS2_FALSE);

    axis2_msg_ctx_set_to(msg_ctx, env, axis2_endpoint_ref_create(env, request_uri));
    axis2_msg_ctx_set_server_side(msg_ctx, env, AXIS2_TRUE);

#ifdef AXIS2_JSON_ENABLED
    if (content_type && strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_JSON))
    {
        /* axis2_msg_ctx_set_doing_json(msg_ctx, env, AXIS2_TRUE); */
    }
    else
#endif
    if(content_type && strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_TEXT_XML))
    {
        if(soap_action_header)
        {
            do_rest = AXIS2_FALSE;
        }
    }
    else if(content_type && strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_APPL_SOAP))
    {
        do_rest = AXIS2_FALSE;
    }

    if(do_rest)
    {
        axis2_msg_ctx_set_doing_rest(msg_ctx, env, AXIS2_TRUE);
        axis2_msg_ctx_set_rest_http_method(msg_ctx, env, AXIS2_HTTP_GET);
    }
    else
    {
        axis2_msg_ctx_set_doing_rest(msg_ctx, env, AXIS2_FALSE);
    }

    if(AXIS2_SUCCESS != axis2_http_transport_utils_dispatch_and_verify(env, msg_ctx))
    {
        return AXIS2_FALSE;
    }
    soap_envelope = axis2_http_transport_utils_handle_media_type_url_encoded(env, msg_ctx,
        request_params, AXIS2_HTTP_GET);
    if(!soap_envelope)
    {
        return AXIS2_FALSE;
    }
    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;
}

AXIS2_EXTERN axis2_bool_t AXIS2_CALL
axis2_http_transport_utils_process_http_delete_request(
    const axutil_env_t * env,
    axis2_msg_ctx_t * msg_ctx,
    axutil_stream_t * in_stream,
    axutil_stream_t * out_stream,
    const axis2_char_t * content_type,
    axutil_string_t * soap_action_header,
    const axis2_char_t * request_uri,
    axis2_conf_ctx_t * conf_ctx,
    axutil_hash_t * request_params)
{
    axiom_soap_envelope_t *soap_envelope = NULL;
    axis2_engine_t *engine = NULL;
    axis2_bool_t do_rest = AXIS2_TRUE;

    AXIS2_PARAM_CHECK(env->error, msg_ctx, AXIS2_FALSE);
    AXIS2_PARAM_CHECK(env->error, in_stream, AXIS2_FALSE);
    AXIS2_PARAM_CHECK(env->error, out_stream, AXIS2_FALSE);
    AXIS2_PARAM_CHECK(env->error, request_uri, AXIS2_FALSE);

    axis2_msg_ctx_set_to(msg_ctx, env, axis2_endpoint_ref_create(env, request_uri));
    axis2_msg_ctx_set_server_side(msg_ctx, env, AXIS2_TRUE);

#ifdef AXIS2_JSON_ENABLED
    if (content_type && strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_JSON))
    {
        /* axis2_msg_ctx_set_doing_json(msg_ctx, env, AXIS2_TRUE); */
    }
    else
#endif
    if(content_type && strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_TEXT_XML))
    {
        if(soap_action_header)
        {
            do_rest = AXIS2_FALSE;
        }
    }
    else if(content_type && strstr(content_type, AXIS2_HTTP_HEADER_ACCEPT_APPL_SOAP))
    {
        do_rest = AXIS2_FALSE;
    }

    if(do_rest)
    {
        axis2_msg_ctx_set_doing_rest(msg_ctx, env, AXIS2_TRUE);
        axis2_msg_ctx_set_rest_http_method(msg_ctx, env, AXIS2_HTTP_DELETE);
    }
    else
    {
        axis2_msg_ctx_set_doing_rest(msg_ctx, env, AXIS2_FALSE);
    }

    if(AXIS2_SUCCESS != axis2_http_transport_utils_dispatch_and_verify(env, msg_ctx))
    {
        return AXIS2_FALSE;
    }

    soap_envelope = axis2_http_transport_utils_handle_media_type_url_encoded(env, msg_ctx,
        request_params, AXIS2_HTTP_DELETE);
    if(!soap_envelope)
    {
        return AXIS2_FALSE;
    }
    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;
}

AXIS2_EXTERN axis2_bool_t AXIS2_CALL
axis2_http_transport_utils_do_write_mtom(
    const axutil_env_t * env,
    axis2_msg_ctx_t * msg_ctx)
{
    AXIS2_PARAM_CHECK(env->error, msg_ctx, AXIS2_FAILURE);

    return (axis2_msg_ctx_get_doing_mtom(msg_ctx, env));
}

AXIS2_EXTERN axutil_hash_t *AXIS2_CALL
axis2_http_transport_utils_get_request_params(
    const axutil_env_t * env,
    axis2_char_t * request_uri)
{

    axis2_char_t *query_str = NULL;
    axis2_char_t *tmp = strchr(request_uri, AXIS2_Q_MARK);
    axis2_char_t *tmp2 = NULL;
    axis2_char_t *tmp_name = NULL;
    axis2_char_t *tmp_value = NULL;
    axutil_hash_t *ret = NULL;

    AXIS2_PARAM_CHECK(env->error, request_uri, NULL);

    if(!tmp || AXIS2_ESC_NULL == *(tmp + 1))
    {
        return NULL;
    }
    query_str = axutil_strdup(env, tmp + 1);

    for(tmp2 = tmp = query_str; *tmp != AXIS2_ESC_NULL; ++tmp)
    {
        if(AXIS2_EQ == *tmp)
        {
            *tmp = AXIS2_ESC_NULL;
            tmp_name = axutil_strdup(env, tmp2);
            axis2_http_transport_utils_strdecode(env, tmp_name, tmp_name);
            tmp2 = tmp + 1;
        }
        if(AXIS2_AND == *tmp)
        {
            *tmp = AXIS2_ESC_NULL;
            tmp_value = axutil_strdup(env, tmp2);
            axis2_http_transport_utils_strdecode(env, tmp_value, tmp_value);
            tmp2 = tmp + 1;
        }
        if(tmp_name && NULL != tmp_value)
        {
            if(!ret)
            {
                ret = axutil_hash_make(env);
            }
            axutil_hash_set(ret, tmp_name, AXIS2_HASH_KEY_STRING, tmp_value);
            /* AXIS2C-1632: Free the key after hash_set since hash copies it internally. */
            AXIS2_FREE(env->allocator, tmp_name);
            tmp_name = NULL;
            tmp_value = NULL;
        }
    }
    /* AXIS2C-1532: Handle the last parameter after the loop ends.
     * Previously this required *tmp2 != '\0', which skipped parameters with
     * empty values (e.g., "param1=value1&param2=" would skip param2).
     * Now we allow empty values - axutil_strdup of an empty string is valid. */
    if(tmp_name)
    {
        if(!ret)
        {
            ret = axutil_hash_make(env);
        }
        tmp_value = axutil_strdup(env, tmp2);
        axis2_http_transport_utils_strdecode(env, tmp_value, tmp_value);
        axutil_hash_set(ret, tmp_name, AXIS2_HASH_KEY_STRING, tmp_value);
        /* AXIS2C-1632: Free the key after hash_set since hash copies it internally. */
        AXIS2_FREE(env->allocator, tmp_name);
        tmp_name = NULL;
    }

    /* AXIS2C-1702: Free the duplicated query string */
    AXIS2_FREE(env->allocator, query_str);

    return ret;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_http_transport_utils_strdecode(
    const axutil_env_t * env,
    axis2_char_t * dest,
    axis2_char_t * src)
{
    AXIS2_PARAM_CHECK(env->error, dest, AXIS2_FAILURE);
    AXIS2_PARAM_CHECK(env->error, src, AXIS2_FAILURE);

    for(; *src != AXIS2_ESC_NULL; ++dest, ++src)
    {
        if(src[0] == AXIS2_PERCENT && isxdigit((int)src[1]) && isxdigit((int)src[2]))
        {
            *dest = (axis2_char_t)(axis2_http_transport_utils_hexit(src[1]) * 16
                + axis2_http_transport_utils_hexit(src[2]));
            /* We are sure that the conversion is valid */
            src += 2;
        }
        else
        {
            *dest = *src;
        }
    }
    *dest = AXIS2_ESC_NULL;

    return AXIS2_SUCCESS;
}

AXIS2_EXTERN int AXIS2_CALL
axis2_http_transport_utils_hexit(
    axis2_char_t c)
{
    if(c >= '0' && c <= '9')
    {
        return c - '0';
    }
    if(c >= 'a' && c <= 'f')
    {
        return c - 'a' + 10;
    }
    if(c >= 'A' && c <= 'F')
    {
        return c - 'A' + 10;
    }
    return 0; /* shouldn't happen, we're guarded by isxdigit() */
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_not_found(
    const axutil_env_t * env,
    axis2_conf_ctx_t * conf_ctx)
{
    return AXIS2_HTTP_NOT_FOUND;
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_not_implemented(
    const axutil_env_t * env,
    axis2_conf_ctx_t * conf_ctx)
{
    return AXIS2_HTTP_NOT_IMPLEMENTED;
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_internal_server_error(
    const axutil_env_t * env,
    axis2_conf_ctx_t * conf_ctx)
{
    return AXIS2_HTTP_INTERNAL_SERVER_ERROR;
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_method_not_allowed(
    const axutil_env_t * env,
    axis2_conf_ctx_t * conf_ctx)
{
    return AXIS2_HTTP_METHOD_NOT_ALLOWED;
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_not_acceptable(
    const axutil_env_t * env,
    axis2_conf_ctx_t * conf_ctx)
{
    return AXIS2_HTTP_NOT_ACCEPTABLE;
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_bad_request(
    const axutil_env_t * env,
    axis2_conf_ctx_t * conf_ctx)
{
    return AXIS2_HTTP_BAD_REQUEST;
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_request_timeout(
    const axutil_env_t * env,
    axis2_conf_ctx_t * conf_ctx)
{
    return AXIS2_HTTP_REQUEST_TIMEOUT;
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_conflict(
    const axutil_env_t * env,
    axis2_conf_ctx_t * conf_ctx)
{
    return AXIS2_HTTP_CONFLICT;
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_gone(
    const axutil_env_t * env,
    axis2_conf_ctx_t * conf_ctx)
{
    return AXIS2_HTTP_GONE;
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_precondition_failed(
    const axutil_env_t * env,
    axis2_conf_ctx_t * conf_ctx)
{
    return AXIS2_HTTP_PRECONDITION_FAILED;
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_request_entity_too_large(
    const axutil_env_t * env,
    axis2_conf_ctx_t * conf_ctx)
{
    return AXIS2_HTTP_TOO_LARGE;
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_service_unavailable(
    const axutil_env_t * env,
    axis2_conf_ctx_t * conf_ctx)
{
    return AXIS2_HTTP_SERVICE_UNAVILABLE;
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_services_html(
    const axutil_env_t * env,
    axis2_conf_ctx_t * conf_ctx)
{
    axutil_hash_t *services_map = NULL;
    axutil_hash_t *errorneous_svc_map = NULL;
    axis2_char_t *ret = NULL;
    axis2_char_t *tmp2 = (axis2_char_t *)"<h2>Deployed Services</h2>";
    axutil_hash_index_t *hi = NULL;
    axis2_bool_t svcs_exists = AXIS2_FALSE;
    axis2_conf_t *conf = NULL;
    AXIS2_PARAM_CHECK(env->error, conf_ctx, NULL);

    conf = axis2_conf_ctx_get_conf(conf_ctx, env);

    /* REVOLUTIONARY: Use service provider interface instead of direct engine calls */
    axis2_http_service_provider_t* service_provider = axis2_http_service_provider_get_impl(env);
    if (service_provider) {
        services_map = service_provider->get_all_services(service_provider, env, conf_ctx);
        errorneous_svc_map = service_provider->get_faulty_services(service_provider, env, conf_ctx);
    } else {
        /* REVOLUTIONARY: Service provider not available - return empty maps */
        /* This should not happen in normal operation since engine registers service provider */
        AXIS2_LOG_WARNING(env->log, AXIS2_LOG_SI,
            "HTTP service provider not available - services list will be empty");
        services_map = NULL;
        errorneous_svc_map = NULL;
    }
    if(services_map && 0 != axutil_hash_count(services_map))
    {
        void *service = NULL;
        axis2_char_t *sname = NULL;
        axutil_hash_t *ops = NULL;
        svcs_exists = AXIS2_TRUE;

        for(hi = axutil_hash_first(services_map, env); hi; hi = axutil_hash_next(env, hi))
        {
            axutil_hash_this(hi, NULL, NULL, &service);
            /* REVOLUTIONARY: SOAP baggage elimination - use clean service provider interface */
            sname = service_provider->get_service_name(service_provider, env, service);
            ret = axutil_stracat(env, tmp2, "<h3><u>");
            tmp2 = ret;
            ret = axutil_stracat(env, tmp2, sname);
            AXIS2_FREE(env->allocator, tmp2);
            tmp2 = ret;
            ret = axutil_stracat(env, tmp2, "</u></h3>");
            tmp2 = ret;
            ret = axutil_stracat(env, tmp2, "<p>");
            tmp2 = ret;

            /**
             *setting services description */
            /* REVOLUTIONARY: Clean interface call instead of direct engine dependency */
            ret = axutil_stracat(env, tmp2, service_provider->get_service_description(service_provider, env, service));
            tmp2 = ret;
            ret = axutil_stracat(env, tmp2, "</p>");
            tmp2 = ret;
            /* REVOLUTIONARY: Use service provider interface for operations */
            ops = service_provider->get_service_operations(service_provider, env, service);
            if(ops && 0 != axutil_hash_count(ops))
            {
                axutil_hash_index_t *hi2 = NULL;
                void *op = NULL;
                axis2_char_t *oname = NULL;

                ret = axutil_stracat(env, tmp2, "<i>Available Operations</i> <ul>");
                AXIS2_FREE(env->allocator, tmp2);
                tmp2 = ret;
                for(hi2 = axutil_hash_first(ops, env); hi2; hi2 = axutil_hash_next(env, hi2))
                {
                    axutil_hash_this(hi2, NULL, NULL, &op);
                    /* REVOLUTIONARY: SOAP baggage elimination for operation names */
                    oname = service_provider->get_operation_name(service_provider, env, op);
                    ret = axutil_stracat(env, tmp2, "<li>");
                    AXIS2_FREE(env->allocator, tmp2);
                    tmp2 = ret;

                    ret = axutil_stracat(env, tmp2, oname);
                    AXIS2_FREE(env->allocator, tmp2);
                    tmp2 = ret;
                    ret = axutil_stracat(env, tmp2, "</li>");
                    AXIS2_FREE(env->allocator, tmp2);
                    tmp2 = ret;
                }
                ret = axutil_stracat(env, tmp2, "</ul>");
                AXIS2_FREE(env->allocator, tmp2);
                tmp2 = ret;
            }
            else
            {
                ret = axutil_stracat(env, tmp2, "No operations Available");
                tmp2 = ret;
            }
        }
    }

    if(errorneous_svc_map && 0 != axutil_hash_count(errorneous_svc_map))
    {
        void *fsname = NULL;
        svcs_exists = AXIS2_TRUE;
        ret = axutil_stracat(env, tmp2,
            "<hr><h2><font color=\"red\">Faulty \
        Services</font></h2>");
        AXIS2_FREE(env->allocator, tmp2);
        tmp2 = ret;

        for(hi = axutil_hash_first(errorneous_svc_map, env); hi; axutil_hash_next(env, hi))
        {
            axutil_hash_this(hi, (const void **)&fsname, NULL, NULL);
            ret = axutil_stracat(env, tmp2, "<h3><font color=\"red\">");
            AXIS2_FREE(env->allocator, tmp2);
            tmp2 = ret;
            ret = axutil_stracat(env, tmp2, (axis2_char_t *)fsname);
            AXIS2_FREE(env->allocator, tmp2);
            tmp2 = ret;
            ret = axutil_stracat(env, tmp2, "</font></h3>");
            AXIS2_FREE(env->allocator, tmp2);
            tmp2 = ret;
        }
    }
    if(AXIS2_FALSE == svcs_exists)
    {
        ret = axutil_strdup(env, "<h2>There are no services deployed</h2>");
    }
    ret = axutil_stracat(env, "<html><head><title>Axis2C :: Services</title></head>"
        "<body><font face=\"courier\">", tmp2);
    tmp2 = ret;
    ret = axutil_stracat(env, tmp2, "</font></body></html>\r\n");

    return ret;
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_services_static_wsdl(
    const axutil_env_t * env,
    axis2_conf_ctx_t * conf_ctx,
    axis2_char_t * request_url)
{
    axis2_char_t *wsdl_string = NULL;
    axis2_char_t *wsdl_path = NULL;
    axis2_char_t **url_tok = NULL;
    axis2_char_t *svc_name = NULL;
    axis2_conf_t *conf = NULL;
    axutil_hash_t *services_map = NULL;
    axutil_hash_index_t *hi = NULL;

    AXIS2_PARAM_CHECK(env->error, conf_ctx, NULL);
    AXIS2_PARAM_CHECK(env->error, request_url, NULL);

    url_tok = axutil_parse_request_url_for_svc_and_op(env, request_url);
    if(url_tok[0])
    {
        /* AXIS2C-1651: Use url_tok[0] directly. The previous code did
         * url_tok[0][len - 5] = 0 trying to remove "?wsdl", but
         * axutil_parse_request_url_for_svc_and_op already returns the
         * service name WITHOUT the query string. The old code caused:
         * - Memory corruption for service names < 5 chars (negative index)
         * - Service name truncation for names >= 5 chars (couldn't find service) */
        svc_name = url_tok[0];
    }

    conf = axis2_conf_ctx_get_conf(conf_ctx, env);

    /* REVOLUTIONARY: Use service provider interface instead of direct engine calls */
    axis2_http_service_provider_t* service_provider = axis2_http_service_provider_get_impl(env);
    if (service_provider) {
        services_map = service_provider->get_all_services(service_provider, env, conf_ctx);
    } else {
        /* REVOLUTIONARY: Service provider not available - return empty map */
        /* This should not happen in normal operation since engine registers service provider */
        AXIS2_LOG_WARNING(env->log, AXIS2_LOG_SI,
            "HTTP service provider not available - services list will be empty");
        services_map = NULL;
    }

    if(services_map && 0 != axutil_hash_count(services_map))
    {
        void *service = NULL;
        axis2_char_t *sname = NULL;

        for(hi = axutil_hash_first(services_map, env); hi; hi = axutil_hash_next(env, hi))
        {
            axutil_hash_this(hi, NULL, NULL, &service);
            /* REVOLUTIONARY: SOAP baggage elimination - use clean service provider interface */
            sname = service_provider->get_service_name(service_provider, env, service);
            if(!axutil_strcmp(svc_name, sname))
            {
                /* REVOLUTIONARY: Use service provider interface for WSDL path */
                const axis2_char_t* service_wsdl = service_provider->get_service_wsdl_path(service_provider, env, service);
                wsdl_path = service_wsdl ? (axis2_char_t *)axutil_strdup(env, service_wsdl) : NULL;
                if(!wsdl_path)
                {
                    /* REVOLUTIONARY: Use service provider interface for folder path */
                    const axis2_char_t* service_folder = service_provider->get_service_folder_path(service_provider, env, service);
                    wsdl_path = service_folder ? axutil_strcat(env, service_folder, AXIS2_PATH_SEP_STR, svc_name, ".wsdl", NULL) : NULL;
                }
                /* AXIS2C-1596: Free hash iterator when breaking early */
                axutil_hash_index_free(hi, env);
                break;
            }

        }
    }

    if(wsdl_path)
    {
        FILE *wsdl_file = NULL;
        axis2_char_t *content = NULL;
        int c;
        size_t size = AXIS2_FILE_READ_SIZE;
        axis2_char_t *tmp;
        size_t i = 0;

        content = (axis2_char_t *)AXIS2_MALLOC(env->allocator, size);
        wsdl_file = fopen(wsdl_path, "r");
        if(wsdl_file)
        {
            c = fgetc(wsdl_file);
            while(c != EOF)
            {
                if(i >= size)
                {
                    size = size * 3;
                    tmp = (axis2_char_t *)AXIS2_MALLOC(env->allocator, size);
                    memcpy(tmp, content, i);
                    AXIS2_FREE(env->allocator, content);
                    content = tmp;
                }
                content[i++] = (axis2_char_t)c;
                c = fgetc(wsdl_file);
            }
            content[i] = AXIS2_ESC_NULL;
            wsdl_string = (axis2_char_t *)content;
			fclose(wsdl_file);
        }
		
        AXIS2_FREE(env->allocator, wsdl_path);
    }
    else
    {
        wsdl_string = axutil_strdup(env, "Unable to retrieve wsdl for this service");
    }

    /* AXIS2C-1596: Free URL tokens allocated by axutil_parse_request_url_for_svc_and_op */
    if(url_tok)
    {
        if(url_tok[0])
        {
            AXIS2_FREE(env->allocator, url_tok[0]);
        }
        if(url_tok[1])
        {
            AXIS2_FREE(env->allocator, url_tok[1]);
        }
        AXIS2_FREE(env->allocator, url_tok);
    }

    return wsdl_string;
}

AXIS2_EXTERN axutil_string_t *AXIS2_CALL
axis2_http_transport_utils_get_charset_enc(
    const axutil_env_t * env,
    const axis2_char_t * content_type)
{
    axis2_char_t *tmp = NULL;
    axis2_char_t *tmp_content_type = NULL;
    axis2_char_t *tmp2 = NULL;
    axutil_string_t *str = NULL;

    AXIS2_PARAM_CHECK(env->error, content_type, NULL);

    tmp_content_type = (axis2_char_t *)content_type;
    if(!tmp_content_type)
    {
        return axutil_string_create_const(env,
            (axis2_char_t **)&AXIS2_TRANS_UTIL_DEFAULT_CHAR_ENCODING);
    }

    tmp = strstr(tmp_content_type, AXIS2_HTTP_CHAR_SET_ENCODING);

    if(tmp)
    {
        tmp = strchr(tmp, AXIS2_EQ);
        if(tmp)
        {
            tmp2 = strchr(tmp, AXIS2_SEMI_COLON);
            if(!tmp2)
            {
                tmp2 = tmp + strlen(tmp);
            }
        }

        if(tmp2)
        {
            if('\'' == *(tmp2 - sizeof(axis2_char_t)) || '\"' == *(tmp2 - sizeof(axis2_char_t)))
            {
                tmp2 -= sizeof(axis2_char_t);
            }
            *tmp2 = AXIS2_ESC_NULL;
        }
    }

    if(tmp)
    {
        /* Following formats are acceptable
         * charset="UTF-8"
         * charser='UTF-8'
         * charset=UTF-8
         * But for our requirements charset we get should be UTF-8
         */
        if(AXIS2_ESC_SINGLE_QUOTE == *(tmp + sizeof(axis2_char_t)) || AXIS2_ESC_DOUBLE_QUOTE
            == *(tmp + sizeof(axis2_char_t)))
        {
            tmp += 2 * sizeof(axis2_char_t);
        }
        else
        {
            tmp += sizeof(axis2_char_t);
        }
    }

    if(tmp)
    {
        str = axutil_string_create(env, tmp);
    }
    else
    {
        str = axutil_string_create_const(env,
            (axis2_char_t **)&AXIS2_TRANS_UTIL_DEFAULT_CHAR_ENCODING);
    }
    return str;
}

int AXIS2_CALL
axis2_http_transport_utils_on_data_request(
    char *buffer,
    int size,  /* Must be int to match AXIS2_READ_INPUT_CALLBACK signature */
    void *ctx)
{
    const axutil_env_t *env = NULL;
    int len = -1;  /* Keep as int: stream functions return -1 on error */
    axis2_callback_info_t *cb_ctx = (axis2_callback_info_t *)ctx;

    if(!buffer || !ctx)
    {
        return 0;
    }
    env = ((axis2_callback_info_t *)ctx)->env;
    if(cb_ctx->unread_len <= 0 && -1 != cb_ctx->content_length)
    {
        return 0;
    }
    if(cb_ctx->chunked_stream)
    {
        --size;
        /* reserve space to insert trailing null */
        len = axutil_http_chunked_stream_read(cb_ctx->chunked_stream, env, buffer, size);
        if(len >= 0)
        {
            buffer[len] = AXIS2_ESC_NULL;
        }
    }
    else
    {
        axutil_stream_t *in_stream = NULL;
        in_stream = (axutil_stream_t *)((axis2_callback_info_t *)ctx)->in_stream;
        --size; /* reserve space to insert trailing null */
        len = axutil_stream_read(in_stream, env, buffer, size);
        if(len > 0)
        {
            buffer[len] = AXIS2_ESC_NULL;
            ((axis2_callback_info_t *)ctx)->unread_len -= len;
        }
        else if(len == 0)
        {
            ((axis2_callback_info_t *)ctx)->unread_len = 0;
        }
    }
    return len;
}

AXIS2_EXTERN axiom_soap_envelope_t *AXIS2_CALL
axis2_http_transport_utils_create_soap_msg(
    const axutil_env_t * env,
    axis2_msg_ctx_t * msg_ctx,
    const axis2_char_t * soap_ns_uri)
{
    axis2_op_ctx_t *op_ctx = NULL;
    const axis2_char_t *char_set_enc = NULL;
    axis2_char_t *content_type = NULL;
    axutil_stream_t *in_stream = NULL;
    axis2_callback_info_t *callback_ctx = NULL;
    axis2_char_t *trans_enc = NULL;
    int *content_length = NULL;
    axutil_property_t *property = NULL;
    axutil_hash_t *binary_data_map = NULL;
    axiom_soap_envelope_t *soap_envelope = NULL;
    axutil_stream_t *stream = NULL;

    AXIS2_PARAM_CHECK(env->error, msg_ctx, NULL);
    AXIS2_PARAM_CHECK(env->error, soap_ns_uri, NULL);

    property = axis2_msg_ctx_get_property(msg_ctx, env, AXIS2_TRANSPORT_IN);
    if(property)
    {
        in_stream = axutil_property_get_value(property, env);
        property = NULL;
    }
    callback_ctx = AXIS2_MALLOC(env->allocator, sizeof(axis2_callback_info_t));
    /* Note: the memory created above is freed in xml reader free function
     as this is passed on to the reader */
    if(!callback_ctx)
    {
        AXIS2_HANDLE_ERROR(env, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
        return NULL;
    }
    callback_ctx->in_stream = in_stream;
    callback_ctx->env = env;
    callback_ctx->content_length = -1;
    callback_ctx->unread_len = -1;
    callback_ctx->chunked_stream = NULL;

    property = axis2_msg_ctx_get_property(msg_ctx, env, AXIS2_HTTP_HEADER_CONTENT_LENGTH);
    if(property)
    {
        content_length = axutil_property_get_value(property, env);
        property = NULL;
    }

    if(content_length)
    {
        callback_ctx->content_length = *content_length;
        callback_ctx->unread_len = *content_length;
    }

    if(!in_stream)
    {
        AXIS2_HANDLE_ERROR(env, AXIS2_ERROR_NULL_IN_STREAM_IN_MSG_CTX, AXIS2_FAILURE);
        AXIS2_FREE(env->allocator, callback_ctx);
        return NULL;
    }

    trans_enc = axis2_msg_ctx_get_transfer_encoding(msg_ctx, env);

    if(trans_enc && 0 == axutil_strcmp(trans_enc, AXIS2_HTTP_HEADER_TRANSFER_ENCODING_CHUNKED))
    {
        callback_ctx->chunked_stream = axutil_http_chunked_stream_create(env, in_stream);
        if(!callback_ctx->chunked_stream)
        {
            return NULL;
        }
    }

    op_ctx = axis2_msg_ctx_get_op_ctx(msg_ctx, env);
    if(op_ctx)
    {
        axis2_ctx_t *ctx = axis2_op_ctx_get_base(op_ctx, env);
        if(ctx)
        {
            property = axis2_ctx_get_property(ctx, env, AXIS2_CHARACTER_SET_ENCODING);
            if(property)
            {
                char_set_enc = axutil_property_get_value(property, env);
                property = NULL;
            }
            property = axis2_ctx_get_property(ctx, env, MTOM_RECIVED_CONTENT_TYPE);
            if(property)
            {
                content_type = axutil_property_get_value(property, env);
                property = NULL;
            }

        }
    }

    if(!char_set_enc)
    {
        char_set_enc = AXIS2_DEFAULT_CHAR_SET_ENCODING;
    }
    if(content_type)
    {
        axis2_char_t *mime_boundary = NULL;
        axis2_msg_ctx_set_doing_mtom(msg_ctx, env, AXIS2_TRUE);
        /* get mime boundry */
        mime_boundary = axis2_http_transport_utils_get_value_from_content_type(env, content_type,
            AXIS2_HTTP_HEADER_CONTENT_TYPE_MIME_BOUNDARY);

        if(mime_boundary)
        {
            axiom_mime_parser_t *mime_parser = NULL;
            size_t soap_body_len = 0;
            axis2_char_t *soap_body_str = NULL;
            axutil_param_t *buffer_size_param = NULL;
            axutil_param_t *max_buffers_param = NULL;
            axutil_param_t *attachment_dir_param = NULL;
            axutil_param_t *callback_name_param = NULL;
            axis2_char_t *value_size = NULL;
            axis2_char_t *value_num = NULL;
            axis2_char_t *value_dir = NULL;
            axis2_char_t *value_callback = NULL;
            size_t size = 0;
            int num = 0;  /* num is count, not size */

            mime_parser = axiom_mime_parser_create(env);

            /* Following are the parameters in the axis2.xml regarding MTOM */

            buffer_size_param = axis2_msg_ctx_get_parameter(msg_ctx, env, AXIS2_MTOM_BUFFER_SIZE);
            if(buffer_size_param)
            {
                value_size = (axis2_char_t *)axutil_param_get_value(buffer_size_param, env);

                if(value_size)
                {
                    size = atoi(value_size);
                    axiom_mime_parser_set_buffer_size(mime_parser, env, size);
                }
            }

            max_buffers_param = axis2_msg_ctx_get_parameter(msg_ctx, env, AXIS2_MTOM_MAX_BUFFERS);
            if(max_buffers_param)
            {
                value_num = (axis2_char_t *)axutil_param_get_value(max_buffers_param, env);
                if(value_num)
                {
                    num = atoi(value_num);
                    axiom_mime_parser_set_max_buffers(mime_parser, env, num);
                }
            }

            callback_name_param = axis2_msg_ctx_get_parameter(msg_ctx, env,
                AXIS2_MTOM_CACHING_CALLBACK);
            if(callback_name_param)
            {
                value_callback = (axis2_char_t *)axutil_param_get_value(callback_name_param, env);
                if(value_callback)
                {
                    axiom_mime_parser_set_caching_callback_name(mime_parser, env, value_callback);
                }
            }

            attachment_dir_param = axis2_msg_ctx_get_parameter(msg_ctx, env, AXIS2_ATTACHMENT_DIR);
            if(attachment_dir_param)
            {
                value_dir = (axis2_char_t *)axutil_param_get_value(attachment_dir_param, env);
                if(value_dir)
                {
                    axiom_mime_parser_set_attachment_dir(mime_parser, env, value_dir);
                }
            }

            if(mime_parser)
            {
                if(axiom_mime_parser_parse_for_soap(mime_parser, env,
                    axis2_http_transport_utils_on_data_request, (void *)callback_ctx, mime_boundary)
                    == AXIS2_FAILURE)
                {
                    return NULL;
                }

                binary_data_map = axiom_mime_parser_parse_for_attachments(mime_parser, env,
                    axis2_http_transport_utils_on_data_request, (void *)callback_ctx,
                    mime_boundary, NULL);
                if(!binary_data_map)
                {
                    return NULL;
                }

                soap_body_len = (int)axiom_mime_parser_get_soap_body_len(mime_parser, env);
                soap_body_str = axiom_mime_parser_get_soap_body_str(mime_parser, env);
            }

            if(callback_ctx->chunked_stream)
            {
                axutil_http_chunked_stream_free(callback_ctx->chunked_stream, env);
                callback_ctx->chunked_stream = NULL;
            }

            stream = axutil_stream_create_basic(env);
            if(stream)
            {
                axutil_stream_write(stream, env, soap_body_str, soap_body_len);
                callback_ctx->in_stream = stream;
                callback_ctx->chunked_stream = NULL;
                callback_ctx->content_length = soap_body_len;
                callback_ctx->unread_len = soap_body_len;
            }

            axiom_mime_parser_free(mime_parser, env);
            mime_parser = NULL;
            if(mime_boundary)
            {
                AXIS2_FREE(env->allocator, mime_boundary);
            }

            if(soap_body_str)
            {
                AXIS2_FREE(env->allocator, soap_body_str);
            }
        }
    }

    if(AXIS2_TRUE != axis2_msg_ctx_get_doing_rest(msg_ctx, env))
    {
        axiom_xml_reader_t *xml_reader = NULL;
        axiom_stax_builder_t *om_builder = NULL;
        axiom_soap_builder_t *soap_builder = NULL;

        xml_reader = axiom_xml_reader_create_for_io(env,
            axis2_http_transport_utils_on_data_request, NULL, (void *)callback_ctx, char_set_enc);
        if(!xml_reader)
        {
            return NULL;
        }
        om_builder = axiom_stax_builder_create(env, xml_reader);
        if(!om_builder)
        {
            axiom_xml_reader_free(xml_reader, env);
            xml_reader = NULL;
            return NULL;
        }
        soap_builder = axiom_soap_builder_create(env, om_builder, soap_ns_uri);
        if(!soap_builder)
        {
            /* We should not be freeing om_builder here as it is done by
             axiom_soap_builder_create in case of error - Samisa */
            om_builder = NULL;
            xml_reader = NULL;
            return NULL;
        }

        soap_envelope = axiom_soap_builder_get_soap_envelope(soap_builder, env);

        if(binary_data_map)
        {
            axiom_soap_builder_set_mime_body_parts(soap_builder, env, binary_data_map);
        }


        if(stream)
        {
            axutil_stream_free(stream, env);
            callback_ctx->in_stream = NULL;
        }
        if(callback_ctx->chunked_stream)
        {
            axutil_http_chunked_stream_free(callback_ctx->chunked_stream, env);
            callback_ctx->chunked_stream = NULL;
        }

    }
    else
    {
        /* REST processing */
        axiom_xml_reader_t *xml_reader = NULL;
        axiom_stax_builder_t *om_builder = NULL;
        axiom_soap_body_t *def_body = NULL;
        axiom_document_t *om_doc = NULL;
        axiom_node_t *root_node = NULL;

        xml_reader = axiom_xml_reader_create_for_io(env,
            axis2_http_transport_utils_on_data_request, NULL, (void *)callback_ctx, char_set_enc);
        if(!xml_reader)
        {
            return NULL;
        }
        om_builder = axiom_stax_builder_create(env, xml_reader);
        if(!om_builder)
        {
            axiom_xml_reader_free(xml_reader, env);
            xml_reader = NULL;
            return NULL;
        }
        soap_envelope = axiom_soap_envelope_create_default_soap_envelope(env, AXIOM_SOAP11);
        def_body = axiom_soap_envelope_get_body(soap_envelope, env);
        om_doc = axiom_stax_builder_get_document(om_builder, env);
        if (!om_doc)
            return AXIS2_FAILURE;
        root_node = axiom_document_get_root_element(om_doc, env);
        if (!root_node)
            return NULL;
        root_node = axiom_document_build_all(om_doc, env);
        axiom_soap_body_add_child(def_body, env, root_node);
        axiom_stax_builder_free_self(om_builder, env);

        if(stream)
        {
            axutil_stream_free(stream, env);
            callback_ctx->in_stream = NULL;
        }
        if(callback_ctx->chunked_stream)
        {
            axutil_http_chunked_stream_free(callback_ctx->chunked_stream, env);
            callback_ctx->chunked_stream = NULL;
        }

    }

    return soap_envelope;
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_value_from_content_type(
    const axutil_env_t * env,
    const axis2_char_t * content_type,
    const axis2_char_t * key)
{
    axis2_char_t *tmp = NULL;
    axis2_char_t *tmp_content_type = NULL;
    axis2_char_t *tmp2 = NULL;

    AXIS2_PARAM_CHECK(env->error, content_type, NULL);
    AXIS2_PARAM_CHECK(env->error, key, NULL);

    tmp_content_type = axutil_strdup(env, content_type);
    if(!tmp_content_type)
    {
        return NULL;
    }
    tmp = strstr(tmp_content_type, key);
    if(!tmp)
    {
        AXIS2_FREE(env->allocator, tmp_content_type);
        return NULL;
    }

    tmp = strchr(tmp, AXIS2_EQ);
    if(!tmp)
    {
        AXIS2_FREE(env->allocator, tmp_content_type);
        return NULL;
    }

    tmp2 = strchr(tmp, AXIS2_SEMI_COLON);
    if(tmp2)
    {
        *tmp2 = AXIS2_ESC_NULL;
    }

    tmp2 = axutil_strdup(env, tmp + 1);

    AXIS2_FREE(env->allocator, tmp_content_type);
    if(!tmp2)
    {
        return NULL;
    }
    if(*tmp2 == AXIS2_DOUBLE_QUOTE)
    {
        tmp = tmp2;
        tmp2 = axutil_strdup(env, tmp + 1);
        if(tmp)
        {
            AXIS2_FREE(env->allocator, tmp);
            tmp = NULL;
        }
        if(!tmp2)
        {
            return NULL;
        }
        tmp2[strlen(tmp2) - 1] = AXIS2_ESC_NULL;
    }
    /* handle XOP */
    if(tmp2 && *tmp2 == AXIS2_B_SLASH && *(tmp2 + 1) == '\"')
    {
        tmp = tmp2;
        tmp2 = axutil_strdup(env, tmp + 2);
        if(tmp)
        {
            AXIS2_FREE(env->allocator, tmp);
            tmp = NULL;
        }
        if(!tmp2)
        {
            return NULL;
        }
        tmp2[strlen(tmp2) - 3] = AXIS2_ESC_NULL;
    }
    return tmp2;
}

AXIS2_EXTERN axiom_soap_envelope_t *AXIS2_CALL
axis2_http_transport_utils_handle_media_type_url_encoded(
    const axutil_env_t * env,
    axis2_msg_ctx_t * msg_ctx,
    axutil_hash_t * param_map,
    axis2_char_t * method)
{
    axiom_soap_envelope_t *soap_env = NULL;
    axiom_soap_body_t *soap_body = NULL;
    /*axiom_element_t *body_child = NULL; */
    axiom_node_t *body_child_node = NULL;
    axiom_node_t *body_element_node = NULL;

    AXIS2_PARAM_CHECK(env->error, msg_ctx, NULL);
    AXIS2_PARAM_CHECK(env->error, method, NULL);

    soap_env = axis2_msg_ctx_get_soap_envelope(msg_ctx, env);

    if(!soap_env)
    {
        soap_env = axiom_soap_envelope_create_default_soap_envelope(env, AXIOM_SOAP11);
    }
    soap_body = axiom_soap_envelope_get_body(soap_env, env);
    if(!soap_body)
    {
        AXIS2_HANDLE_ERROR(env, AXIS2_ERROR_SOAP_ENVELOPE_OR_SOAP_BODY_NULL, AXIS2_FAILURE);
        return NULL;
    }

    body_element_node = axiom_soap_body_get_base_node(soap_body, env);

    if(body_element_node)
    {
        body_child_node = axiom_node_get_first_child(body_element_node, env);
    }

    if(!body_child_node)
    {
        if(!axis2_msg_ctx_get_op(msg_ctx, env))
        {
            return NULL;
        }
        /*body_child = */
        /* REVOLUTIONARY: Avoid circular dependency - create simple element without engine dependency */
        axiom_element_create(env, NULL, "operation", NULL, &body_child_node);
        axiom_soap_body_add_child(soap_body, env, body_child_node);
    }
    if(param_map)
    {
        axutil_hash_index_t *hi = NULL;
        for(hi = axutil_hash_first(param_map, env); hi; hi = axutil_hash_next(env, hi))
        {
            void *name = NULL;
            void *value = NULL;
            axiom_node_t *node = NULL;
            axiom_element_t *element = NULL;

            axutil_hash_this(hi, (const void **)&name, NULL, (void **)&value);
            element = axiom_element_create(env, NULL, (axis2_char_t *)name, NULL, &node);
            axiom_element_set_text(element, env, (axis2_char_t *)value, node);
            axiom_node_add_child(body_child_node, env, node);
        }
    }
    return soap_env;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_http_transport_utils_dispatch_and_verify(
    const axutil_env_t * env,
    axis2_msg_ctx_t * msg_ctx)
{
    axis2_disp_t *rest_disp = NULL;
    axis2_handler_t *handler = NULL;

    AXIS2_PARAM_CHECK(env->error, msg_ctx, AXIS2_FAILURE);

    if(axis2_msg_ctx_get_doing_rest(msg_ctx, env))
    {
		axis2_handler_desc_t *desc;
        rest_disp = axis2_rest_disp_create(env);
        handler = axis2_disp_get_base(rest_disp, env);
        axis2_handler_invoke(handler, env, msg_ctx);
		axis2_disp_free(rest_disp, env);
		desc = axis2_handler_get_handler_desc(handler, env);
		if(desc)
		{
			axis2_handler_desc_free(desc, env);
		}

        if(!axis2_msg_ctx_get_svc(msg_ctx, env) || !axis2_msg_ctx_get_op(msg_ctx, env))
        {
            AXIS2_HANDLE_ERROR(env, AXIS2_ERROR_SVC_OR_OP_NOT_FOUND, AXIS2_FAILURE);
            return AXIS2_FAILURE;
        }
    }

    return AXIS2_SUCCESS;
}

AXIS2_EXTERN axutil_array_list_t *AXIS2_CALL
axis2_http_transport_utils_process_accept_headers(
    const axutil_env_t *env,
    axis2_char_t *accept_value)
{
    axutil_array_list_t *accept_field_list = NULL;
    axutil_array_list_t *accept_record_list = NULL;
    accept_field_list = axutil_tokenize(env, accept_value, ',');
    if(accept_field_list && axutil_array_list_size(accept_field_list, env) > 0)
    {
        axis2_char_t *token = NULL;
        accept_record_list = axutil_array_list_create(env, axutil_array_list_size(
            accept_field_list, env));
        do
        {
            if(token)
            {
                axis2_http_accept_record_t *rec = NULL;
                rec = axis2_http_accept_record_create(env, token);
                if(rec)
                {
					axutil_array_list_add(accept_record_list, env, rec);
                }
                AXIS2_FREE(env->allocator, token);
            }
            token = (axis2_char_t *)axutil_array_list_remove(accept_field_list, env, 0);
        }
        while(token);
    }
    if(accept_record_list && axutil_array_list_size(accept_record_list, env) > 0)
    {
        return accept_record_list;
    }
    return NULL;
}

int
axis2_http_transport_utils_check_status_code(
    int status_code)
{
    int status = AXIS2_HTTP_RESPONSE_OK_CODE_VAL;
    switch(status_code)
    {
        case AXIS2_HTTP_RESPONSE_CONTINUE_CODE_VAL:
            status = AXIS2_HTTP_RESPONSE_CONTINUE_CODE_VAL;
            break;
        case AXIS2_HTTP_RESPONSE_ACK_CODE_VAL:
            status = AXIS2_HTTP_RESPONSE_ACK_CODE_VAL;
            break;
        case AXIS2_HTTP_RESPONSE_MULTIPLE_CHOICES_CODE_VAL:
            status = AXIS2_HTTP_RESPONSE_MULTIPLE_CHOICES_CODE_VAL;
            break;
        case AXIS2_HTTP_RESPONSE_MOVED_PERMANENTLY_CODE_VAL:
            status = AXIS2_HTTP_RESPONSE_MULTIPLE_CHOICES_CODE_VAL;
            break;
        case AXIS2_HTTP_RESPONSE_SEE_OTHER_CODE_VAL:
            status = AXIS2_HTTP_RESPONSE_SEE_OTHER_CODE_VAL;
            break;
        case AXIS2_HTTP_RESPONSE_NOT_MODIFIED_CODE_VAL:
            status = AXIS2_HTTP_RESPONSE_NOT_MODIFIED_CODE_VAL;
            break;
        case AXIS2_HTTP_RESPONSE_TEMPORARY_REDIRECT_CODE_VAL:
            status = AXIS2_HTTP_RESPONSE_TEMPORARY_REDIRECT_CODE_VAL;
            break;
        case AXIS2_HTTP_RESPONSE_BAD_REQUEST_CODE_VAL:
            status = AXIS2_HTTP_RESPONSE_BAD_REQUEST_CODE_VAL;
            break;
        case AXIS2_HTTP_RESPONSE_REQUEST_TIMEOUT_CODE_VAL:
            status = AXIS2_HTTP_RESPONSE_REQUEST_TIMEOUT_CODE_VAL;
            break;
        case AXIS2_HTTP_RESPONSE_CONFLICT_CODE_VAL:
            status = AXIS2_HTTP_RESPONSE_CONFLICT_CODE_VAL;
            break;
        case AXIS2_HTTP_RESPONSE_GONE_CODE_VAL:
            status = AXIS2_HTTP_RESPONSE_GONE_CODE_VAL;
            break;
        case AXIS2_HTTP_RESPONSE_PRECONDITION_FAILED_CODE_VAL:
            status = AXIS2_HTTP_RESPONSE_PRECONDITION_FAILED_CODE_VAL;
            break;
        case AXIS2_HTTP_RESPONSE_REQUEST_ENTITY_TOO_LARGE_CODE_VAL:
            status = AXIS2_HTTP_RESPONSE_REQUEST_ENTITY_TOO_LARGE_CODE_VAL;
            break;
        case AXIS2_HTTP_RESPONSE_SERVICE_UNAVAILABLE_CODE_VAL:
            status = AXIS2_HTTP_RESPONSE_SERVICE_UNAVAILABLE_CODE_VAL;
            break;
    }
    return status;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_http_transport_utils_process_request(
    const axutil_env_t *env,
    axis2_conf_ctx_t *conf_ctx,
    axis2_http_transport_in_t *request,
    axis2_http_transport_out_t *response)
{
    axis2_status_t status = AXIS2_FAILURE;
    axis2_msg_ctx_t *msg_ctx = NULL;
    axutil_stream_t *out_stream = NULL;
    axutil_string_t *soap_action = NULL;
    axis2_bool_t processed = AXIS2_FALSE;
    axis2_char_t *body_string = NULL;
    axis2_char_t *ctx_uuid = NULL;
    axis2_op_ctx_t *op_ctx = NULL;
    axis2_char_t *peer_ip = NULL;
    axutil_property_t *peer_property = NULL;
    axis2_msg_ctx_t *out_msg_ctx = NULL;
    axis2_msg_ctx_t **msg_ctx_map = NULL;

    AXIS2_ENV_CHECK(env, AXIS2_CRITICAL_FAILURE);
    AXIS2_PARAM_CHECK(env->error, request, AXIS2_CRITICAL_FAILURE);
    AXIS2_PARAM_CHECK(env->error, request->request_uri, AXIS2_FALSE);

    if(!conf_ctx)
    {
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NULL_CONFIGURATION_CONTEXT, AXIS2_FAILURE);
        return AXIS2_CRITICAL_FAILURE;
    }

    if(!request->content_type)
    {
        request->content_type = AXIS2_HTTP_HEADER_ACCEPT_TEXT_PLAIN;
    }

    /** creating the out stream */
    out_stream = axutil_stream_create_basic(env);

    if(request->transfer_encoding)
        axis2_msg_ctx_set_transfer_encoding(request->msg_ctx, env, request->transfer_encoding);

    axis2_msg_ctx_set_server_side(request->msg_ctx, env, AXIS2_TRUE);
    msg_ctx = request->msg_ctx;
    peer_ip = request->remote_ip;

    if(peer_ip)
    {
        peer_property = axutil_property_create(env);
        axutil_property_set_value(peer_property, env, axutil_strdup(env, peer_ip));
        axis2_msg_ctx_set_property(msg_ctx, env, AXIS2_SVR_PEER_IP_ADDR, peer_property);
    }

    axis2_msg_ctx_set_transport_out_stream(msg_ctx, env, out_stream);

    ctx_uuid = axutil_uuid_gen(env);
    if(ctx_uuid)
    {
        axutil_string_t *uuid_str = axutil_string_create_assume_ownership(env, &ctx_uuid);
        axis2_msg_ctx_set_svc_grp_ctx_id(msg_ctx, env, uuid_str);
        axutil_string_free(uuid_str, env);
    }

    axis2_msg_ctx_set_out_transport_info(msg_ctx, env,
        &(request->out_transport_info->out_transport));

    if(request->accept_header)
    {
        axutil_array_list_t *accept_record_list = NULL;
        accept_record_list = axis2_http_transport_utils_process_accept_headers(env,
            request->accept_header);
        if(accept_record_list && axutil_array_list_size(accept_record_list, env) > 0)
        {
            axis2_msg_ctx_set_http_accept_record_list(msg_ctx, env, accept_record_list);
        }
    }
    if(request->accept_charset_header)
    {
        axutil_array_list_t *accept_charset_record_list = NULL;
        accept_charset_record_list = axis2_http_transport_utils_process_accept_headers(env,
            request->accept_charset_header);
        if(accept_charset_record_list)
        {
            axis2_msg_ctx_set_http_accept_charset_record_list(msg_ctx, env,
                accept_charset_record_list);
        }
    }
    if(request->accept_language_header)
    {
        axutil_array_list_t *accept_language_record_list = NULL;
        accept_language_record_list = axis2_http_transport_utils_process_accept_headers(env,
            request->accept_language_header);
        if(accept_language_record_list)
        {
            axis2_msg_ctx_set_http_accept_language_record_list(msg_ctx, env,
                accept_language_record_list);
        }
    }

    if(request->soap_action)
    {
        soap_action = axutil_string_create(env, request->soap_action);
    }

    if(request->request_method == AXIS2_HTTP_METHOD_GET || request->request_method
        == AXIS2_HTTP_METHOD_DELETE || request->request_method == AXIS2_HTTP_METHOD_HEAD)
    {

        if(request->request_method == AXIS2_HTTP_METHOD_DELETE)
        {
            processed = axis2_http_transport_utils_process_http_delete_request(env,
                request->msg_ctx, request->in_stream, out_stream, request->content_type,
                soap_action, request->request_uri, conf_ctx,
                axis2_http_transport_utils_get_request_params(env, request->request_uri));
        }
        else if(request->request_method == AXIS2_HTTP_METHOD_HEAD)
        {
            processed = axis2_http_transport_utils_process_http_head_request(env, request->msg_ctx,
                request->in_stream, out_stream, request->content_type, soap_action,
                request->request_uri, conf_ctx, axis2_http_transport_utils_get_request_params(env,
                    request->request_uri));
        }
        else if(request->request_method == AXIS2_HTTP_METHOD_GET)
        {
            processed = axis2_http_transport_utils_process_http_get_request(env, request->msg_ctx,
                request->in_stream, out_stream, request->content_type, soap_action,
                request->request_uri, conf_ctx, axis2_http_transport_utils_get_request_params(env,
                    request->request_uri));
        }
        if(AXIS2_FALSE == processed)
        {
            axis2_bool_t is_services_path = AXIS2_FALSE;
            int msg_ctx_status_code = axis2_msg_ctx_get_status_code(msg_ctx, env);
            if(request->request_method != AXIS2_HTTP_METHOD_DELETE && request->request_url_prefix)
            {
                axis2_char_t *temp = NULL;
                temp = strstr(request->request_uri, request->request_url_prefix);
                if(temp)
                {
                    temp += strlen(request->request_url_prefix);
                    if(*temp == '/')
                    {
                        temp++;
                    }
                    if(!*temp || *temp == '?' || *temp == '#')
                    {
                        is_services_path = AXIS2_TRUE;
                    }
                }
            }
            if(is_services_path)
            {
                body_string = axis2_http_transport_utils_get_services_html(env, conf_ctx);
                response->content_type = AXIS2_HTTP_HEADER_ACCEPT_TEXT_HTML;
                response->http_status_code = AXIS2_HTTP_RESPONSE_OK_CODE_VAL;
                response->http_status_code_name = AXIS2_HTTP_RESPONSE_OK_CODE_NAME;
            }
            else if(AXIS2_HTTP_METHOD_DELETE != request->request_method)
            {
                axis2_char_t *wsdl = NULL;
                wsdl = strstr(request->request_uri, AXIS2_REQUEST_WSDL);
                if(wsdl)
                {
                    body_string = axis2_http_transport_utils_get_services_static_wsdl(env,
                        conf_ctx, request->request_uri);
                    response->content_type = AXIS2_HTTP_HEADER_ACCEPT_TEXT_XML;
                    response->http_status_code = AXIS2_HTTP_RESPONSE_OK_CODE_VAL;
                    response->http_status_code_name = AXIS2_HTTP_RESPONSE_OK_CODE_NAME;
                }
            }
            else if(env->error->error_number == AXIS2_ERROR_SVC_OR_OP_NOT_FOUND)
            {
                axutil_array_list_t *method_list = NULL;
                size_t size = 0;
                method_list = axis2_msg_ctx_get_supported_rest_http_methods(msg_ctx, env);
                size = (size_t)axutil_array_list_size(method_list, env);

                if(method_list && size)
                {
                    /** 405 */
                    body_string = axis2_http_transport_utils_get_method_not_allowed(env, conf_ctx);

                    response->http_status_code = AXIS2_HTTP_RESPONSE_METHOD_NOT_ALLOWED_CODE_VAL;
                    response->http_status_code_name
                    = AXIS2_HTTP_RESPONSE_METHOD_NOT_ALLOWED_CODE_NAME;
                }
                else
                {
                    /** 404  */
                    body_string = axis2_http_transport_utils_get_not_found(env, conf_ctx);
                    response->http_status_code = AXIS2_HTTP_RESPONSE_NOT_FOUND_CODE_VAL;
                    response->http_status_code_name = AXIS2_HTTP_RESPONSE_NOT_FOUND_CODE_NAME;
                }
            }
            else if(msg_ctx_status_code == AXIS2_HTTP_RESPONSE_BAD_REQUEST_CODE_VAL)
            {
                /* 400, Bad Request */
                body_string = axis2_http_transport_utils_get_bad_request(env, conf_ctx);
                response->http_status_code = AXIS2_HTTP_RESPONSE_BAD_REQUEST_CODE_VAL;
                response->http_status_code_name = AXIS2_HTTP_RESPONSE_BAD_REQUEST_CODE_NAME;

            }
            else if(msg_ctx_status_code == AXIS2_HTTP_RESPONSE_REQUEST_TIMEOUT_CODE_VAL)
            {
                /* 408, Request Timeout */
                body_string = axis2_http_transport_utils_get_request_timeout(env, conf_ctx);
                response->http_status_code = AXIS2_HTTP_RESPONSE_REQUEST_TIMEOUT_CODE_VAL;
                response->http_status_code_name = AXIS2_HTTP_RESPONSE_REQUEST_TIMEOUT_CODE_NAME;
            }
            else if(msg_ctx_status_code == AXIS2_HTTP_RESPONSE_CONFLICT_CODE_VAL)
            {
                /* 409, Conflict Types */
                body_string = axis2_http_transport_utils_get_conflict(env, conf_ctx);
                response->http_status_code = AXIS2_HTTP_RESPONSE_CONFLICT_CODE_VAL;
                response->http_status_code_name = AXIS2_HTTP_RESPONSE_CONFLICT_CODE_NAME;
            }
            else if(msg_ctx_status_code == AXIS2_HTTP_RESPONSE_GONE_CODE_VAL)
            {
                /* 410, Gone. Resource no longer available */
                body_string = axis2_http_transport_utils_get_gone(env, conf_ctx);
                response->http_status_code = AXIS2_HTTP_RESPONSE_GONE_CODE_VAL;
                response->http_status_code_name = AXIS2_HTTP_RESPONSE_GONE_CODE_NAME;

            }
            else if(msg_ctx_status_code == AXIS2_HTTP_RESPONSE_PRECONDITION_FAILED_CODE_VAL)
            {
                /*410, Precondition for the url failed  */
                body_string = axis2_http_transport_utils_get_precondition_failed(env, conf_ctx);
                response->http_status_code = AXIS2_HTTP_RESPONSE_PRECONDITION_FAILED_CODE_VAL;
                response->http_status_code_name = AXIS2_HTTP_RESPONSE_PRECONDITION_FAILED_CODE_NAME;

            }
            else if(msg_ctx_status_code == AXIS2_HTTP_RESPONSE_REQUEST_ENTITY_TOO_LARGE_CODE_VAL)
            {
                /* 413, Request entity too large */
                body_string
                = axis2_http_transport_utils_get_request_entity_too_large(env, conf_ctx);
                response->http_status_code = AXIS2_HTTP_RESPONSE_REQUEST_ENTITY_TOO_LARGE_CODE_VAL;
                response->http_status_code_name
                = AXIS2_HTTP_RESPONSE_REQUEST_ENTITY_TOO_LARGE_CODE_NAME;
            }
            else if(msg_ctx_status_code == AXIS2_HTTP_RESPONSE_SERVICE_UNAVAILABLE_CODE_VAL)
            {
                /* 513, Service Unavailable */
                body_string = axis2_http_transport_utils_get_service_unavailable(env, conf_ctx);
                response->http_status_code = AXIS2_HTTP_RESPONSE_SERVICE_UNAVAILABLE_CODE_VAL;
                response->http_status_code_name = AXIS2_HTTP_RESPONSE_SERVICE_UNAVAILABLE_CODE_NAME;
            }
            else
            {
                /* 500, Internal Server Error */
                body_string = axis2_http_transport_utils_get_internal_server_error(env, conf_ctx);
                response->http_status_code = AXIS2_HTTP_RESPONSE_INTERNAL_SERVER_ERROR_CODE_VAL;
                response->http_status_code_name
                = AXIS2_HTTP_RESPONSE_INTERNAL_SERVER_ERROR_CODE_NAME;
            }

            if(body_string)
            {
                response->response_data = body_string;
                response->response_data_length = axutil_strlen(body_string);
            }
            status = AXIS2_SUCCESS;
        }
    }
    else if(AXIS2_HTTP_METHOD_POST == request->request_method || AXIS2_HTTP_METHOD_PUT
        == request->request_method)
    {
        if(AXIS2_HTTP_METHOD_POST == request->request_method)
        {
            processed = axis2_http_transport_utils_process_http_post_request(env, request->msg_ctx,
                request->in_stream, out_stream, request->content_type, request->content_length,
                soap_action, request->request_uri);
        }
        else
        {
            processed = axis2_http_transport_utils_process_http_put_request(env, request->msg_ctx,
                request->in_stream, out_stream, request->content_type, request->content_length,
                soap_action, request->request_uri);
        }
        if(AXIS2_FAILURE == processed && (AXIS2_HTTP_METHOD_PUT == request->request_method
            || axis2_msg_ctx_get_doing_rest(msg_ctx, env)))
        {

            if(env->error->error_number == AXIS2_ERROR_SVC_OR_OP_NOT_FOUND)
            {
                axutil_array_list_t *method_list = NULL;
                size_t size = 0;
                method_list = axis2_msg_ctx_get_supported_rest_http_methods(msg_ctx, env);
                size = (size_t)axutil_array_list_size(method_list, env);
                if(method_list && size)
                {
                    /** 405 */
                    body_string = axis2_http_transport_utils_get_method_not_allowed(env, conf_ctx);
                    response->http_status_code = AXIS2_HTTP_RESPONSE_METHOD_NOT_ALLOWED_CODE_VAL;
                    response->http_status_code_name
                    = AXIS2_HTTP_RESPONSE_METHOD_NOT_ALLOWED_CODE_NAME;
                }
                else
                {
                    /** 404  */
                    body_string = axis2_http_transport_utils_get_not_found(env, conf_ctx);
                    response->http_status_code = AXIS2_HTTP_RESPONSE_NOT_FOUND_CODE_VAL;
                    response->http_status_code_name = AXIS2_HTTP_RESPONSE_NOT_FOUND_CODE_NAME;
                }
                request->content_type = AXIS2_HTTP_HEADER_ACCEPT_TEXT_HTML;
            }
            else
            {
                /* 500, Internal Server Error */
                body_string = axis2_http_transport_utils_get_internal_server_error(env, conf_ctx);
                response->http_status_code = AXIS2_HTTP_RESPONSE_INTERNAL_SERVER_ERROR_CODE_VAL;
                response->http_status_code_name
                = AXIS2_HTTP_RESPONSE_INTERNAL_SERVER_ERROR_CODE_NAME;

            }

            if(body_string)
            {
                response->response_data = body_string;
                response->response_data_length = axutil_strlen(body_string);
            }
            status = AXIS2_SUCCESS;
        }
        else if(processed == AXIS2_FAILURE)
        {
            axis2_msg_ctx_t *fault_ctx = NULL;
            axis2_char_t *fault_code = NULL;
            axis2_engine_t *engine = axis2_engine_create(env, conf_ctx);
            if(!engine)
            {
                /* Critical error, cannot proceed, send defaults document for 500 */
                return AXIS2_CRITICAL_FAILURE;
            }
            if(axis2_msg_ctx_get_is_soap_11(msg_ctx, env))
            {
                fault_code            = AXIOM_SOAP_DEFAULT_NAMESPACE_PREFIX ":"
                    AXIOM_SOAP11_FAULT_CODE_SENDER;
            }
            else
            {
                fault_code = AXIOM_SOAP_DEFAULT_NAMESPACE_PREFIX ":"
                    AXIOM_SOAP12_SOAP_FAULT_VALUE_SENDER;
            }
            fault_ctx = axis2_engine_create_fault_msg_ctx(engine, env, request->msg_ctx,
                fault_code, axutil_error_get_message(env->error));

            axis2_engine_send_fault(engine, env, fault_ctx);
            if(fault_ctx)
            {
                axis2_msg_ctx_free(fault_ctx, env);
            }
            axis2_engine_free(engine, env);
            if (out_stream)
            {
                response->response_data = axutil_stream_get_buffer(out_stream, env);
                response->response_data_length = axutil_stream_get_len (out_stream, env);
            }
            /* In case of a SOAP Fault, we have to set the status to 500, but still return */
            status = AXIS2_SUCCESS;
            response->http_status_code = AXIS2_HTTP_RESPONSE_INTERNAL_SERVER_ERROR_CODE_VAL;
            response->http_status_code_name = AXIS2_HTTP_RESPONSE_INTERNAL_SERVER_ERROR_CODE_NAME;
        }
    }
    else
    {
        response->response_data = axis2_http_transport_utils_get_not_implemented(env, conf_ctx);
        request->content_type = AXIS2_HTTP_HEADER_ACCEPT_TEXT_HTML;

        if (response->response_data)
        {
            response->response_data_length = axutil_strlen(response->response_data);
        }
        response->http_status_code = AXIS2_HTTP_RESPONSE_NOT_IMPLEMENTED_CODE_VAL;
        response->http_status_code_name = AXIS2_HTTP_RESPONSE_NOT_IMPLEMENTED_CODE_NAME;
        status = AXIS2_SUCCESS;
    }

    op_ctx = axis2_msg_ctx_get_op_ctx(msg_ctx, env);

    if (op_ctx)
    {
        msg_ctx_map = axis2_op_ctx_get_msg_ctx_map(op_ctx, env);
        out_msg_ctx = msg_ctx_map[AXIS2_WSDL_MESSAGE_LABEL_OUT];
        response->msg_ctx = out_msg_ctx;
    }

    if (status == AXIS2_FAILURE)
    {
        axis2_bool_t do_rest = AXIS2_FALSE;
        if (AXIS2_HTTP_METHOD_POST != request->request_method ||
            axis2_msg_ctx_get_doing_rest(msg_ctx, env))
        {
            do_rest = AXIS2_TRUE;
        }
        if ((request->accept_header || request->accept_charset_header ||
            request->accept_language_header) && do_rest)
        {
            axis2_char_t *content_type_header_value = NULL;
            axis2_char_t *temp = NULL;
            axis2_char_t *language_header_value = NULL;

            content_type_header_value = (axis2_char_t *) request->content_type;
            language_header_value = axis2_msg_ctx_get_content_language(out_msg_ctx,env);
            if (content_type_header_value)
            {
                temp = axutil_strdup(env, content_type_header_value);
            }
            if (temp)
            {
                axis2_char_t *content_type = NULL;
                axis2_char_t *char_set = NULL;
                axis2_char_t *temp2 = NULL;

                temp2 = strchr(temp, ';');
                if (temp2)
                {
                    *temp2 = '\0';
                    temp2++;
                    char_set = axutil_strcasestr(temp2, AXIS2_HTTP_CHAR_SET_ENCODING);
                }
                if (char_set)
                {
                    char_set = axutil_strltrim(env, char_set, " \t=");
                }
                if (char_set)
                {
                    temp2 = strchr(char_set, ';');
                }
                if (temp2)
                {
                    *temp2 = '\0';
                }
                content_type = axutil_strtrim(env, temp, NULL);

                if (temp)
                {
                    AXIS2_FREE(env->allocator, temp);
                    temp = NULL;
                }
                if (content_type && request->accept_header &&
                    !axutil_strcasestr(request->accept_header, content_type))
                {
                    temp2 = strchr(content_type, '/');
                    if (temp2)
                    {
                        *temp2 = '\0';
                        temp = AXIS2_MALLOC(env->allocator,
                            sizeof(axis2_char_t) * ((int)strlen(content_type) + 3));
                        if (!temp)
                        {
                            AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
                            return AXIS2_FALSE;
                        }
                        sprintf(temp, "%s/*", content_type);
                        if (!axutil_strcasestr(request->accept_header, temp) &&
                            !strstr(request->accept_header, AXIS2_HTTP_HEADER_ACCEPT_ALL))
                        {
                            response->response_data =
                                axis2_http_transport_utils_get_not_acceptable(env, conf_ctx);
                            response->content_type = AXIS2_HTTP_HEADER_ACCEPT_TEXT_HTML;
                            if (response->response_data)
                            {
                                response->response_data_length = axutil_strlen(response->response_data);
                            }
                            response->http_status_code = AXIS2_HTTP_RESPONSE_NOT_ACCEPTABLE_CODE_VAL;
                            response->http_status_code_name = AXIS2_HTTP_RESPONSE_NOT_IMPLEMENTED_CODE_NAME;
                            status = AXIS2_TRUE;
                        }
                        AXIS2_FREE(env->allocator, temp);
                    }
                }
                if (content_type)
                {
                    AXIS2_FREE(env->allocator, content_type);
                }
                if (char_set && request->accept_charset_header &&
                    !axutil_strcasestr(request->accept_charset_header , char_set))
                {
                    response->response_data =
                        axis2_http_transport_utils_get_not_acceptable(env, conf_ctx);
                    response->content_type = AXIS2_HTTP_HEADER_ACCEPT_TEXT_HTML;

                    if (response->response_data)
                    {
                        response->response_data_length= axutil_strlen(response->response_data);
                    }
                    status = AXIS2_SUCCESS;
                    response->http_status_code = AXIS2_HTTP_RESPONSE_NOT_ACCEPTABLE_CODE_VAL;
                    response->http_status_code_name = AXIS2_HTTP_RESPONSE_NOT_ACCEPTABLE_CODE_NAME;
                }
                if (char_set)
                {
                    AXIS2_FREE(env->allocator, char_set);
                }
            }
            if (language_header_value)
            {
                if (request->accept_language_header &&
                    !axutil_strcasestr(request->accept_language_header , language_header_value))
                {
                    response->response_data =
                        axis2_http_transport_utils_get_not_acceptable(env, conf_ctx);
                    response->content_type = AXIS2_HTTP_HEADER_ACCEPT_TEXT_HTML;
                    if (response->response_data)
                    {
                        response->response_data_length = axutil_strlen(response->response_data);
                    }
                    response->http_status_code = AXIS2_HTTP_RESPONSE_NOT_ACCEPTABLE_CODE_VAL;
                    response->http_status_code_name = AXIS2_HTTP_RESPONSE_NOT_ACCEPTABLE_CODE_NAME;
                }
            }
        }
    }
    if (status == AXIS2_FAILURE)
    {
        axis2_bool_t do_rest = AXIS2_FALSE;
        if (AXIS2_HTTP_METHOD_POST != request->request_method ||
            axis2_msg_ctx_get_doing_rest(msg_ctx, env))
        {
            do_rest = AXIS2_TRUE;
        }
        if (op_ctx && axis2_op_ctx_get_response_written(op_ctx, env))
        {
            if (do_rest)
            {
                if (out_msg_ctx)
                {
                    /*int size = 0; */
                    axutil_array_list_t *output_header_list = NULL;
                    output_header_list = axis2_msg_ctx_get_http_output_headers(out_msg_ctx, env);
                    if (output_header_list)
                    {
                        /*size = axutil_array_list_size(output_header_list, env); */
                        response->output_headers = output_header_list;
                    }

                    if (axis2_msg_ctx_get_status_code(out_msg_ctx, env))
                    {
                        int status_code = axis2_msg_ctx_get_status_code(out_msg_ctx, env);
                        response->http_status_code =
                            axis2_http_transport_utils_check_status_code(status_code);
                        status = AXIS2_SUCCESS;
                    }
                }
            }
            if (status == AXIS2_FAILURE)
            {
                status = AXIS2_SUCCESS;
                if (out_stream)
                {
                    response->response_data = axutil_stream_get_buffer(out_stream, env);
                    response->response_data_length = axutil_stream_get_len(out_stream, env);
                    response->http_status_code = AXIS2_HTTP_RESPONSE_OK_CODE_VAL;
                    response->http_status_code_name = AXIS2_HTTP_RESPONSE_OK_CODE_NAME;
                }
            }
        }
        else if (op_ctx)
        {
            if (do_rest)
            {
                if (out_msg_ctx)
                {
                    /*int size = 0; */
                    axutil_array_list_t *output_header_list = NULL;
                    output_header_list = axis2_msg_ctx_get_http_output_headers(out_msg_ctx, env);
                    if (output_header_list)
                    {
                        /*size = axutil_array_list_size(output_header_list, env);*/
                        response->output_headers = output_header_list;
                    }
                    if (axis2_msg_ctx_get_no_content(out_msg_ctx, env))
                    {
                        if (axis2_msg_ctx_get_status_code(out_msg_ctx, env))
                        {
                            int status_code = axis2_msg_ctx_get_status_code(out_msg_ctx, env);
                            switch (status_code)
                            {
                                case AXIS2_HTTP_RESPONSE_RESET_CONTENT_CODE_VAL:
                                    response->http_status_code = AXIS2_HTTP_RESPONSE_RESET_CONTENT_CODE_VAL;
                                    break;
                                case AXIS2_HTTP_RESPONSE_NOT_MODIFIED_CODE_VAL:
                                    response->http_status_code = AXIS2_HTTP_RESPONSE_NOT_MODIFIED_CODE_VAL;
                                    break;
                                default:
                                    response->http_status_code = AXIS2_HTTP_RESPONSE_NO_CONTENT_CODE_VAL;
                                    break;
                            }
                        }
                        else
                        {
                            response->http_status_code = AXIS2_HTTP_RESPONSE_NO_CONTENT_CODE_VAL;
                        }
                        status = AXIS2_SUCCESS;
                    }
                    else if (axis2_msg_ctx_get_status_code(out_msg_ctx, env))
                    {
                        int status_code = axis2_msg_ctx_get_status_code(out_msg_ctx, env);
                        response->http_status_code =
                            axis2_http_transport_utils_check_status_code(status_code);
                        status = AXIS2_SUCCESS;
                    }
                }
            }
            if (status == AXIS2_FAILURE)
            {
                response->http_status_code = AXIS2_HTTP_RESPONSE_ACK_CODE_VAL;
                response->http_status_code_name = AXIS2_HTTP_RESPONSE_ACK_CODE_NAME;
                status = AXIS2_SUCCESS;
            }
        }
        else
        {
            status = AXIS2_SUCCESS;
            response->http_status_code = AXIS2_HTTP_RESPONSE_ACK_CODE_VAL;
            response->http_status_code_name = AXIS2_HTTP_RESPONSE_ACK_CODE_NAME;
        }
    }
    axutil_string_free(soap_action, env);
    msg_ctx = NULL;

    return status;
}

/* This method takes an array_list as the input. It has items some 
 may be buffers and some may be files. This will send these part
 one by one to the wire using the chunked stream.*/
AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_http_transport_utils_send_mtom_message(
    axutil_http_chunked_stream_t * chunked_stream,
    const axutil_env_t * env,
    axutil_array_list_t *mime_parts,
    axis2_char_t *sending_callback_name)
{
    int i = 0;
    axis2_status_t status = AXIS2_SUCCESS;

    for(i = 0; i < axutil_array_list_size(mime_parts, env); i++)
    {
        axiom_mime_part_t *mime_part = NULL;
        mime_part = (axiom_mime_part_t *)axutil_array_list_get(mime_parts, env, (int)i);

        /* If it is a buffer just write it to the wire. This includes mime_bounadaries,
         * mime_headers and SOAP */
        if(mime_part->type == AXIOM_MIME_PART_BUFFER)
        {
            size_t written = 0;
            while(written < mime_part->part_size)
            {
                int len = 0;
                len = axutil_http_chunked_stream_write(chunked_stream, env,
                    mime_part->part + written, mime_part->part_size - written);
                if(len == -1)
                {
                    status = AXIS2_FAILURE;
                    break;
                }
                else
                {
                    written += len;
                }
            }
        }

        /* If it is a file we load a very little portion to memory and send it as chunked ,
         * we keep on doing this until we find the end of the file */
        else if(mime_part->type == AXIOM_MIME_PART_FILE)
        {
            FILE *f = NULL;
            axis2_byte_t *output_buffer = NULL;
            size_t output_buffer_size = 0;

            f = fopen(mime_part->file_name, "rb");
            if(!f)
            {
                AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Error opening file %s for reading",
                    mime_part->file_name);
                return AXIS2_FAILURE;
            }

            /* If the part_size is less than the defined buffer size then
             * from the first write to the wire we can send the file */
            if(mime_part->part_size > AXIS2_MTOM_OUTPUT_BUFFER_SIZE)
            {
                output_buffer_size = AXIS2_MTOM_OUTPUT_BUFFER_SIZE;
            }
            else
            {
                output_buffer_size = (int)mime_part->part_size;
            }

            output_buffer = AXIS2_MALLOC(env->allocator, output_buffer_size * sizeof(axis2_char_t));

            /*This is the method responsible for writing to the wire */
            status = axis2_http_transport_utils_send_attachment_using_file(env, chunked_stream,
                f, output_buffer, output_buffer_size);
            AXIS2_FREE(env->allocator, output_buffer);
            fclose(f);
        }
        else if((mime_part->type) == AXIOM_MIME_PART_HANDLER) 
        {
            void *handler_data = NULL;
            axiom_mtom_sending_callback_t *callback = NULL;

            status = mime_part->read_handler_create(&callback, env);

            if(callback)
            {
                handler_data = AXIOM_MTOM_SENDING_CALLBACK_INIT_HANDLER(callback, env,
                    mime_part->user_param);

                if (handler_data)
                {
                    status = axis2_http_transport_utils_send_attachment_using_callback(env,
                        chunked_stream, callback, handler_data, mime_part->user_param);
                }
                else
                {
                    AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "MTOM Sending Handler loading failed");
                    status = AXIS2_FAILURE;
                }

                mime_part->read_handler_remove(callback, env);
            }

            if(status == AXIS2_FAILURE)
            {
                return status;
            }
        }
        /* if the callback is given, send data using callback */
        else if((mime_part->type) == AXIOM_MIME_PART_CALLBACK)
        {
            void *handler = NULL;
            axiom_mtom_sending_callback_t *callback = NULL;

            handler = axis2_http_transport_utils_initiate_callback(env, sending_callback_name,
                mime_part->user_param, &callback);
            if(handler)
            {
                status = axis2_http_transport_utils_send_attachment_using_callback(env,
                    chunked_stream, callback, handler, mime_part->user_param);
            }
            else
            {
                AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "MTOM Sending Callback loading failed");
                status = AXIS2_FAILURE;
            }

            if(callback)
            {
                axutil_param_t *param = NULL;
                param = callback->param;
                AXIOM_MTOM_SENDING_CALLBACK_FREE(callback, env);
                if(param)
                {
                    axutil_param_free(param, env);
                }
            }
        }
        else
        {
            AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Unknown mime_part.");
            status = AXIS2_FAILURE;
        }

        if(status != AXIS2_SUCCESS)
        {
            break;
        }
    }

    if(status == AXIS2_SUCCESS)
    {
        /* send the end of chunk */
        status = axutil_http_chunked_stream_write_last_chunk(chunked_stream, env);
    }

    return status;
}

static axis2_status_t
axis2_http_transport_utils_send_attachment_using_file(
    const axutil_env_t * env,
    axutil_http_chunked_stream_t *chunked_stream,
    FILE *fp,
    axis2_byte_t *buffer,
    size_t buffer_size)
{
    /*We do not load the whole file to memory. Just load a buffer_size portion
     *and send it. Keep on doing this until the end of file */
    do
    {
        int written = 0;
        int count = (int)fread(buffer, 1, buffer_size, fp);
        if(ferror(fp) || (count < 0))
        {
            AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
                "Error in reading file containing the attachment");
            return AXIS2_FAILURE;
        }

        /* count == 0 is a valid case. If the file size is multiple of buffer_size, then last read
         * will have count == 0
         */

        /*Writing the part we loaded to memory to the wire*/
        while(written < count)
        {
            int len = axutil_http_chunked_stream_write(chunked_stream, env,
                buffer + written, count - written);
            if(len == -1)
            {
                AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "error in writing file to stream");
                return AXIS2_FAILURE;
            }

            written += len;
        }
    }
    while(!feof(fp));

    return AXIS2_SUCCESS;
}

AXIS2_EXTERN void AXIS2_CALL
axis2_http_transport_utils_destroy_mime_parts(
    axutil_array_list_t *mime_parts,
    const axutil_env_t *env)
{
    if (mime_parts)
    {
        int i = 0;
        for (i = 0; i < axutil_array_list_size(mime_parts, env); i++)
        {
            axiom_mime_part_t *mime_part = NULL;
            mime_part = (axiom_mime_part_t *)
                axutil_array_list_get(mime_parts, env, i);
            if (mime_part)
            {
                axiom_mime_part_free(mime_part, env);
            }
        }
        axutil_array_list_free(mime_parts, env);
    }
}

AXIS2_EXTERN void *AXIS2_CALL
axis2_http_transport_utils_initiate_callback(
    const axutil_env_t *env,
    axis2_char_t *callback_name,
    void *user_param,
    axiom_mtom_sending_callback_t **callback)
{
    axutil_dll_desc_t *dll_desc = NULL;
    axutil_param_t *impl_info_param = NULL;
    void *ptr = NULL;

    if(!callback_name)
    {
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "invalid callback name given");
        return NULL;
    }

    AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "Trying to load module = %s", callback_name);

    dll_desc = axutil_dll_desc_create(env);
    axutil_dll_desc_set_name(dll_desc, env, callback_name);
    impl_info_param = axutil_param_create(env, NULL, dll_desc);
    axutil_param_set_value_free(impl_info_param, env, axutil_dll_desc_free_void_arg);
    axutil_class_loader_init(env);
    ptr = axutil_class_loader_create_dll(env, impl_info_param);
    if (!ptr)
    {
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Unable to load the module %s.", callback_name);
        return NULL;
    }

    *callback = (axiom_mtom_sending_callback_t *)ptr;
    (*callback)->param = impl_info_param;

    return AXIOM_MTOM_SENDING_CALLBACK_INIT_HANDLER(*callback, env, user_param);
}

static axis2_status_t
axis2_http_transport_utils_send_attachment_using_callback(
    const axutil_env_t * env,
    axutil_http_chunked_stream_t *chunked_stream,
    axiom_mtom_sending_callback_t *callback,
    void *handler,
    void *user_param)
{
    int count = 0;
    axis2_status_t status = AXIS2_SUCCESS;
    axis2_char_t *buffer = NULL;

    /* Keep on loading the data in a loop until all the data is sent */
    while((count = AXIOM_MTOM_SENDING_CALLBACK_LOAD_DATA(callback, env, handler, &buffer)) > 0)
    {
        int written = 0;
        while(written < count)
        {
            int len = 0;
            len = axutil_http_chunked_stream_write(chunked_stream, env,
                buffer + written, count - written);
            if(len == -1)
            {
                status = AXIS2_FAILURE;
                break;
            }

            written += len;
        }
    }

    status = AXIOM_MTOM_SENDING_CALLBACK_CLOSE_HANDLER(callback, env, handler) && status;
    return status;
}

AXIS2_EXTERN axis2_bool_t AXIS2_CALL
axis2_http_transport_utils_is_callback_required(
    const axutil_env_t *env,
    axutil_array_list_t *mime_parts)
{
    size_t size = 0;
    size_t i = 0;
    axis2_bool_t is_required = AXIS2_FALSE;

    size = (size_t)axutil_array_list_size(mime_parts, env);
    for(i = 0; i < size; i++)
    {
        axiom_mime_part_t *mime_part = NULL;
        mime_part = (axiom_mime_part_t *)axutil_array_list_get(mime_parts, env, (int)i);
        if(mime_part)
        {
            if(mime_part->type == AXIOM_MIME_PART_CALLBACK)
            {
                is_required = AXIS2_TRUE;
                break;
            }
        }
    }

    return is_required;
}

static void 
axis2_http_transport_utils_parse_session_str(const axutil_env_t *env, axis2_char_t *str, 
        axutil_hash_t *ht)
{
    while (*str)
    {
        axis2_char_t *next = axutil_strstr(str, ";");
        if (next)
        {
            axis2_char_t *key = NULL;
            axis2_char_t *val = NULL;
            

            /* Get key and value pairs */
            key = axis2_http_transport_utils_copy_key(env, str);
            val = axis2_http_transport_utils_copy_value(env, str);
            axutil_hash_set(ht, key, AXIS2_HASH_KEY_STRING, val);

            /* find next token */
            str = next + 1;
        }
           
    }
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_session(
        const axutil_env_t *env, 
        axis2_msg_ctx_t *msg_ctx)
{
    axutil_hash_index_t *hi = NULL;
    void *val = NULL;
    const void *key = NULL;
    axutil_hash_t *ht = NULL;
    axis2_char_t *session_id = NULL;
    axis2_char_t *time_str = NULL;
    axis2_char_t *header_value = NULL;
    axutil_date_time_t *expire_time = NULL;
    axis2_char_t session_value[256];
    /* Use size_t (C89/ANSI C standard) for buffer tracking instead of int:
     * - Unsigned type prevents negative index bugs
     * - Matches sizeof() return type for correct bounds comparisons
     * - Avoids signed/unsigned comparison warnings that can mask real bugs
     * Previously this code used sprintf() in a loop without bounds checking,
     * which could overflow the fixed-size stack buffer with malicious input.
     */
    size_t session_value_len = 0;
    const size_t session_value_max = sizeof(session_value) - 1;
    axis2_http_out_transport_info_t *out_info = NULL;
    axis2_status_t status = AXIS2_SUCCESS;

    AXIS2_LOG_TRACE(env->log, AXIS2_LOG_SI, "Entry:axis2_http_transport_utils_get_session");
    ht = axis2_msg_ctx_get_property_value(msg_ctx, env, AXIS2_TRANSPORT_SESSION_TABLE);
    if(!ht)
    {
        axis2_op_ctx_t *op_ctx = NULL;
        axis2_msg_ctx_t *in_msg_ctx = NULL;
        op_ctx = axis2_msg_ctx_get_op_ctx(msg_ctx, env);
        if(op_ctx)
        {
            in_msg_ctx = axis2_op_ctx_get_msg_ctx(op_ctx, env, AXIS2_WSDL_MESSAGE_LABEL_IN);
            if(in_msg_ctx)
            {
                ht = axis2_msg_ctx_get_property_value(in_msg_ctx, env, 
                        AXIS2_TRANSPORT_SESSION_TABLE);
            }
        }
        if(!ht)
        {
            return NULL;
        }
    }
    session_id = axutil_hash_get(ht, "id", AXIS2_HASH_KEY_STRING);
    if(!session_id)
    {
        /* Generate session and set it in session table */
        session_id = axutil_uuid_gen(env);
        /* AXIS2C-1632: Don't strdup keys - hash_set copies them internally.
         * Values still need to be strdup'd since hash doesn't manage value memory. */
        axutil_hash_set(ht, "id", AXIS2_HASH_KEY_STRING, axutil_strdup(env, session_id));

        /* Generate expire time and set it in session table */
        expire_time = axutil_date_time_create_with_offset(env, AXIS2_TRANSPORT_SESSION_EXPIRE_DURATION);
        time_str = axutil_strdup(env, axutil_date_time_serialize_date_time(expire_time, env));
        axutil_date_time_free(expire_time, env);
        axutil_hash_set(ht, "expires", AXIS2_HASH_KEY_STRING, time_str);
    
        session_value[0] = '\0';
        session_value_len = 0;

        /* Note that in addition to storing the values in the session table into a string, we also
         * free the session table entries in the following loop,  because we are going to store them
         * into the session database.
         */
        for(hi = axutil_hash_first(ht, env); hi; hi = axutil_hash_next(env, hi))
        {
            axis2_char_t *name = NULL;
            axis2_char_t *value = NULL;
            int written = 0;

            axutil_hash_this(hi, &key, NULL, &val);
            name = (axis2_char_t *) key;
            value = (axis2_char_t *) val;
            if(name && session_value_len < session_value_max)
            {
                written = snprintf(session_value + session_value_len,
                                   session_value_max - session_value_len + 1,
                                   "%s=", name);
                if (written > 0)
                {
                    session_value_len += (size_t)written;
                }
                AXIS2_FREE(env->allocator, name);
            }
            if(value && session_value_len < session_value_max)
            {
                written = snprintf(session_value + session_value_len,
                                   session_value_max - session_value_len + 1,
                                   "%s;", value);
                if (written > 0)
                {
                    session_value_len += (size_t)written;
                }
                AXIS2_FREE(env->allocator, value);
            }
        }

        out_info = (axis2_http_out_transport_info_t *)axis2_msg_ctx_get_out_transport_info(
            msg_ctx, env);
        if(!out_info)
        {
            AXIS2_HANDLE_ERROR(env, AXIS2_ERROR_OUT_TRNSPORT_INFO_NULL, AXIS2_FAILURE);
            AXIS2_FREE(env->allocator, header_value);
            return NULL;
        }
        /* Store the session in the session database */
        status = AXIS2_HTTP_OUT_TRANSPORT_INFO_SET_SESSION(out_info, env, session_id, session_value);
        if(status != AXIS2_SUCCESS)
        {
            AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, 
                    "Inserting session value failed for session id %s", session_id);
            return NULL;
        }
    }
    else
    {
        /* This means session is already created in a previous request.*/
        time_str = axutil_hash_get(ht, "expires", AXIS2_HASH_KEY_STRING);
        /* Free the session hash table entries, because session entries are already in the
         * session database.
         */
        for(hi = axutil_hash_first(ht, env); hi; hi = axutil_hash_next(env, hi))
        {
            axis2_char_t *name = NULL;
            axis2_char_t *value = NULL;

            axutil_hash_this(hi, &key, NULL, &val);
            name = (axis2_char_t *) key;
            value = (axis2_char_t *) val;
            if(name)
            {
                AXIS2_FREE(env->allocator, name);
            }
            if(value)
            {
                AXIS2_FREE(env->allocator, value);
            }
        }
    }
    /* Allocate enough for "ID=" + session_id + "; expires=" + time_str + ";" + null */
    {
        size_t header_size = 256;
        if (session_id && time_str)
        {
            header_size = axutil_strlen(session_id) + axutil_strlen(time_str) + 20;
        }
        header_value = AXIS2_MALLOC(env->allocator, header_size);
        if (header_value)
        {
            snprintf(header_value, header_size, "ID=%s; expires=%s;",
                     session_id ? session_id : "",
                     time_str ? time_str : "");
        }
    }

    /* Free the session hash table here */
    axutil_hash_free(ht, env);
    AXIS2_LOG_TRACE(env->log, AXIS2_LOG_SI, "Exit:axis2_http_transport_utils_get_session");
    return header_value;
}

AXIS2_EXTERN void AXIS2_CALL
axis2_http_transport_utils_set_session(
        const axutil_env_t *env, 
        axis2_msg_ctx_t *msg_ctx,
        axis2_char_t *session_str)
{
    axutil_date_time_t *expire_time = NULL;
    axutil_date_time_t *current_time = NULL;
    axutil_date_time_comp_result_t result;
    axis2_char_t *time_str = NULL;
    axutil_hash_t *ht = NULL;
    axutil_property_t *property = NULL;

    AXIS2_LOG_TRACE(env->log, AXIS2_LOG_SI, "Entry:axis2_http_tranpsport_utils_set_session");

    /* Check whether session has expired. If so set error and return */
    ht = axutil_hash_make(env);
    axis2_http_transport_utils_parse_session_str(env, session_str, ht);
    time_str = (axis2_char_t *) axutil_hash_get(ht, "time", AXIS2_HASH_KEY_STRING);
    expire_time = axutil_date_time_create(env);
    axutil_date_time_deserialize_date_time(expire_time, env, time_str);
    current_time = axutil_date_time_create(env);
    result = axutil_date_time_compare(current_time, env, expire_time);
    axutil_date_time_free(current_time, env);
    axutil_date_time_free(expire_time, env);
    if(result == AXIS2_DATE_TIME_COMP_RES_EXPIRED)
    {
        axutil_hash_index_t *hi = NULL;
        void *val = NULL;
        const void *key = NULL;

        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Session time out");
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_SESSION_TIMEOUT, AXIS2_FAILURE);
        for(hi = axutil_hash_first(ht, env); hi; hi = axutil_hash_next(env, hi))
        {
            axis2_char_t *name = NULL;
            axis2_char_t *value = NULL;

            axutil_hash_this(hi, &key, NULL, &val);
            name = (axis2_char_t *) key;
            if(name)
            {
                AXIS2_FREE(env->allocator, name);
            }
            value = (axis2_char_t *) val;
            if(value)
            {
                AXIS2_FREE(env->allocator, value);
            }
        }
        axutil_hash_free(ht, env);
    }
    /* session hash table does not belong to property.*/
    property = axutil_property_create_with_args(env, AXIS2_SCOPE_REQUEST, AXIS2_FALSE, 0, ht);
    axis2_msg_ctx_set_property(msg_ctx, env, AXIS2_TRANSPORT_SESSION_TABLE, property);
    AXIS2_LOG_TRACE(env->log, AXIS2_LOG_SI, "Exit:axis2_http_tranpsport_utils_set_session");
}

/**
 * After receiving Set-Cookie header store it
 */
AXIS2_EXTERN void AXIS2_CALL
axis2_http_transport_utils_store_cookie(
        const axutil_env_t *env, 
        axis2_msg_ctx_t *msg_ctx, 
        axis2_char_t *cookie)
{
    axis2_conf_ctx_t *conf_ctx = NULL;
    axutil_property_t *property = NULL;
    axutil_hash_t *session_map = NULL;
    axis2_endpoint_ref_t *endpoint = NULL;
    const axis2_char_t *address = NULL;

    AXIS2_LOG_TRACE(env->log, AXIS2_LOG_SI, "Entry:axis2_http_transport_utils_store_cookie");
    conf_ctx = axis2_msg_ctx_get_conf_ctx(msg_ctx, env);
    property = axis2_conf_ctx_get_property(conf_ctx, env, AXIS2_TRANSPORT_SESSION_MAP);
    if(property)
    {
        session_map = axutil_property_get_value(property, env);
    }
    if(!session_map)
    {
        if(!cookie)
        {
            AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, 
                    "No session map found and no cookie set. So return");
            return;
        }
        session_map = axutil_hash_make(env);
        if(session_map)
        {
            property = axutil_property_create_with_args(env, AXIS2_SCOPE_APPLICATION, 1, 
                axis2_http_transport_utils_session_map_free_void_arg, session_map); 
            axis2_conf_ctx_set_property(conf_ctx, env, AXIS2_TRANSPORT_SESSION_MAP, property);
        }
        else
        {
            AXIS2_HANDLE_ERROR(env, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
            return;
        }
    }
    endpoint = axis2_msg_ctx_get_to(msg_ctx, env);
    if(endpoint)
    {
        address = axis2_endpoint_ref_get_address(endpoint, env);
        if(address)
        {
            axutil_url_t *url = NULL;

            url = axutil_url_parse_string(env, address);
            if(url)
            {
                axis2_char_t *server = NULL;
                server = axutil_url_get_server(url, env);
                if(server)
                {
                    if(cookie)
                    {
                        /* AXIS2C-1632: Don't strdup keys - hash_set copies them internally. */
                        axutil_hash_set(session_map, server, AXIS2_HASH_KEY_STRING,
                                axutil_strdup(env, cookie));
                    }
                    else /* We remove any cookie set for this endpoint */
                    {
                        cookie = axutil_hash_get(session_map, server, AXIS2_HASH_KEY_STRING);
                        if(cookie)
                        {
                            AXIS2_FREE(env->allocator, cookie);
                        }
                        axutil_hash_set(session_map, server, AXIS2_HASH_KEY_STRING, NULL);
                    }
                }
                axutil_url_free(url, env);
            }
        }
    }

    AXIS2_LOG_TRACE(env->log, AXIS2_LOG_SI, "Exit:axis2_http_transport_utils_store_cookie");
}

/* Read from cookie store before sending */
AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_read_from_cookie_store(
        const axutil_env_t *env, 
        axis2_msg_ctx_t *msg_ctx)
{
    axutil_property_t *property = NULL;
    axutil_hash_t *session_map = NULL;
    axis2_endpoint_ref_t *endpoint = NULL;
    const axis2_char_t *address = NULL;
    axis2_char_t *cookie = NULL;
    axis2_conf_ctx_t *conf_ctx = NULL;

    AXIS2_LOG_TRACE(env->log, AXIS2_LOG_SI, "Entry:axis2_http_transport_utils_read_from_cookie_store");
    conf_ctx = axis2_msg_ctx_get_conf_ctx(msg_ctx, env);
    property = axis2_conf_ctx_get_property(conf_ctx, env, AXIS2_TRANSPORT_SESSION_MAP);
    if(property)
    {
        session_map = axutil_property_get_value(property, env);
    }
    if(!session_map)
    {
        AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "No session map stored");
        return NULL;
    }
    endpoint = axis2_msg_ctx_get_to(msg_ctx, env);
    if(endpoint)
    {
        address = axis2_endpoint_ref_get_address(endpoint, env);
        if(address)
        {
            axutil_url_t *url = NULL; 
            url = axutil_url_parse_string(env, address);
            if(url)
            {
                axis2_char_t *server = NULL;
                server = axutil_url_get_server(url, env);
                if(server)
                {
                    cookie = axutil_hash_get(session_map, server, AXIS2_HASH_KEY_STRING);
                }
                axutil_url_free(url, env);
            }
            AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "cookie:%s", cookie);
        }
    }
    
    AXIS2_LOG_TRACE(env->log, AXIS2_LOG_SI, "Exit:axis2_http_transport_utils_read_from_cookie_store");
    return cookie;
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_http_transport_utils_get_session_id_from_cookie(
        const axutil_env_t *env,
        axis2_char_t *cookie)
{
    /* AXIS2C-1608: Always try to extract session ID from the first cookie.
     * The old code only worked if there was a semicolon in the string,
     * but a single cookie like "sessionid=value" should also work. */
    return axis2_http_transport_utils_copy_value(env, cookie);
}

static axis2_char_t *
axis2_http_transport_utils_copy_key(
        const axutil_env_t *env,
        axis2_char_t *pair)
{
    axis2_char_t *p = axutil_strchr(pair, '=');
    axis2_char_t *ret = NULL;

    /* AXIS2C-1608: Don't modify input string, use axutil_strmemdup instead */
    if (p)
    {
        size_t len = p - pair;
        ret = axutil_strmemdup(pair, len, env);
    }

    return ret;
}

static axis2_char_t *
axis2_http_transport_utils_copy_value(
        const axutil_env_t *env,
        axis2_char_t *pair)
{
    axis2_char_t *ret = NULL;
    axis2_char_t *end = NULL;
    size_t len;

    pair = axutil_strchr(pair, '=');
    if (pair)
    {
        pair++;
        /* AXIS2C-1608: Check if ';' exists, handle last cookie in string.
         * Also don't modify input string as it may be read-only (Apache headers). */
        end = axutil_strchr(pair, ';');
        if (end)
        {
            len = end - pair;
        }
        else
        {
            /* No semicolon - this is the last (or only) cookie */
            len = axutil_strlen(pair);
        }
        ret = axutil_strmemdup(pair, len, env);
    }

    return ret;
}


AXIS2_EXTERN void AXIS2_CALL
axis2_http_transport_utils_session_map_free_void_arg(
    void *sm_void,
    const axutil_env_t *env)
{
    void *val = NULL;
    axutil_hash_index_t *hi = NULL;
    axutil_hash_t *ht = (axutil_hash_t *)sm_void;

    /* Free the cookie values stored in the hash. The keys (server names) are
     * freed by axutil_hash_free() since they were stored with AXIS2_HASH_KEY_STRING
     * which makes internal copies. */
    for(hi = axutil_hash_first(ht, env); hi; hi = axutil_hash_next(env, hi))
    {
        axis2_char_t *value = NULL;

        axutil_hash_this(hi, NULL, NULL, &val);
        value = (axis2_char_t *) val;
        if(value)
        {
            AXIS2_FREE(env->allocator, value);
        }
    }
    axutil_hash_free(ht, env);
}


