blob: 7a7541b2a222449083b80b2eba911a2ce886a28a [file] [log] [blame]
/*
* 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 <axiom_data_handler.h>
#include <stdio.h>
#include <sys/stat.h>
#include <axiom_mime_part.h>
struct axiom_data_handler
{
/* The content type */
axis2_char_t *mime_type;
/* If in a file then the file name*/
axis2_char_t *file_name;
/* If it is in a buffer then the buffer */
axis2_byte_t *buffer;
/* The length of the buffer */
size_t buffer_len;
/* Is this a data_handler with a file name or a buffer*/
axiom_data_handler_type_t data_handler_type;
/* When parsing whether we have cached it or not */
axis2_bool_t cached;
/* The Content Id */
axis2_char_t *mime_id;
/* In the case of TYPE_HANDLER these are required */
int (* read_handler_create)(
axiom_mtom_sending_callback_t ** inst,
const axutil_env_t * env);
int (* read_handler_remove)(
axiom_mtom_sending_callback_t * inst,
const axutil_env_t * env);
/* In the case of sending callback this is required */
void *user_param;
};
/* Creates the data_handler. The file name is not mandatory */
AXIS2_EXTERN axiom_data_handler_t *AXIS2_CALL
axiom_data_handler_create(
const axutil_env_t *env,
const axis2_char_t *file_name,
const axis2_char_t *mime_type)
{
axiom_data_handler_t *data_handler = NULL;
AXIS2_ENV_CHECK(env, NULL);
data_handler = (axiom_data_handler_t *)AXIS2_MALLOC(env->allocator,
sizeof(axiom_data_handler_t));
if(!data_handler)
{
AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "No memory. Cannot create data handler");
return NULL;
}
data_handler->mime_type = NULL;
data_handler->file_name = NULL;
data_handler->buffer = NULL;
data_handler->buffer_len = 0;
/* By default, a Data Handler is of type Buffer */
data_handler->data_handler_type = AXIOM_DATA_HANDLER_TYPE_BUFFER;
data_handler->cached = AXIS2_FALSE;
data_handler->mime_id = NULL;
data_handler->user_param = NULL;
if(mime_type)
{
data_handler->mime_type = axutil_strdup(env, mime_type);
if(!(data_handler->mime_type))
{
axiom_data_handler_free(data_handler, env);
return NULL;
}
}
if(file_name)
{
data_handler->file_name = axutil_strdup(env, file_name);
if(!(data_handler->file_name))
{
axiom_data_handler_free(data_handler, env);
return NULL;
}
data_handler->data_handler_type = AXIOM_DATA_HANDLER_TYPE_FILE;
}
return data_handler;
}
AXIS2_EXTERN void AXIS2_CALL
axiom_data_handler_free(
axiom_data_handler_t *data_handler,
const axutil_env_t *env)
{
if(data_handler->file_name)
{
AXIS2_FREE(env->allocator, data_handler->file_name);
}
if(data_handler->mime_type)
{
AXIS2_FREE(env->allocator, data_handler->mime_type);
}
if(data_handler->buffer)
{
AXIS2_FREE(env->allocator, data_handler->buffer);
}
if(data_handler->mime_id)
{
AXIS2_FREE(env->allocator, data_handler->mime_id);
}
if(data_handler)
{
AXIS2_FREE(env->allocator, data_handler);
}
return;
}
AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axiom_data_handler_get_content_type(
axiom_data_handler_t *data_handler,
const axutil_env_t *env)
{
return data_handler->mime_type;
}
AXIS2_EXTERN axis2_status_t AXIS2_CALL
axiom_data_handler_set_content_type(
axiom_data_handler_t *data_handler,
const axutil_env_t *env,
const axis2_char_t *mime_type)
{
if(data_handler->mime_type)
{
AXIS2_FREE(env->allocator, data_handler->mime_type);
}
data_handler->mime_type = axutil_strdup(env, mime_type);
return AXIS2_SUCCESS;
}
AXIS2_EXTERN axis2_bool_t AXIS2_CALL
axiom_data_handler_get_cached(
axiom_data_handler_t *data_handler,
const axutil_env_t *env)
{
return data_handler->cached;
}
AXIS2_EXTERN void AXIS2_CALL
axiom_data_handler_set_cached(
axiom_data_handler_t *data_handler,
const axutil_env_t *env,
axis2_bool_t cached)
{
data_handler->cached = cached;
}
AXIS2_EXTERN axis2_byte_t *AXIS2_CALL
axiom_data_handler_get_input_stream(
axiom_data_handler_t *data_handler,
const axutil_env_t *env)
{
return data_handler->buffer;
}
AXIS2_EXTERN size_t AXIS2_CALL
axiom_data_handler_get_input_stream_len(
axiom_data_handler_t *data_handler,
const axutil_env_t *env)
{
return data_handler->buffer_len;
}
/* With MTOM caching support this function is no longer used
* Because this will load whole file in to buffer. So for large
* attachment this is not wise */
AXIS2_EXTERN axis2_status_t AXIS2_CALL
axiom_data_handler_read_from(
axiom_data_handler_t *data_handler,
const axutil_env_t *env,
axis2_byte_t **output_stream,
size_t *output_stream_size)
{
if(data_handler->data_handler_type == AXIOM_DATA_HANDLER_TYPE_BUFFER)
{
*output_stream = data_handler->buffer;
*output_stream_size = data_handler->buffer_len;
}
else if(data_handler->data_handler_type == AXIOM_DATA_HANDLER_TYPE_FILE)
{
FILE *f = NULL;
axis2_byte_t *byte_stream = NULL;
axis2_byte_t *temp_byte_stream = NULL;
axis2_byte_t *read_stream = NULL;
int byte_stream_size = 0;
int temp_byte_stream_size = 0;
int read_stream_size = 0;
int count = 0;
struct stat stat_p;
if (!data_handler->file_name)
{
return AXIS2_FAILURE;
}
f = fopen(data_handler->file_name, "rb");
if(!f)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Error opening file %s for reading",
data_handler->file_name);
return AXIS2_FAILURE;
}
if(stat(data_handler->file_name, &stat_p) == -1)
{
fclose(f);
return AXIS2_FAILURE;
}
else if(stat_p.st_size == 0)
{
fclose(f);
*output_stream = NULL;
*output_stream_size = 0;
return AXIS2_SUCCESS;
}
do
{
read_stream_size = stat_p.st_size;
read_stream = AXIS2_MALLOC(env->allocator, (read_stream_size) * sizeof(axis2_byte_t));
if(!read_stream)
{
AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "No memory. Cannot create binary stream");
if(byte_stream)
{
AXIS2_FREE(env->allocator, byte_stream);
}
fclose(f);
return AXIS2_FAILURE;
}
count = (int)fread(read_stream, 1, read_stream_size, f);
/* The count lies within the int range */
if(ferror(f))
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Error in reading file %s",
data_handler->file_name);
if(byte_stream)
{
AXIS2_FREE(env->allocator, byte_stream);
}
if(read_stream)
{
AXIS2_FREE(env->allocator, read_stream);
}
fclose(f);
return AXIS2_FAILURE;
}
/* copy the read bytes */
if(count > 0)
{
if(byte_stream)
{
temp_byte_stream = byte_stream;
temp_byte_stream_size = byte_stream_size;
byte_stream_size = temp_byte_stream_size + count;
byte_stream = AXIS2_MALLOC(env->allocator, (byte_stream_size)
* sizeof(axis2_byte_t));
if(!byte_stream)
{
AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"No memory. Cannot create binary stream");
if(read_stream)
{
AXIS2_FREE(env->allocator, read_stream);
}
if(temp_byte_stream)
{
AXIS2_FREE(env->allocator, temp_byte_stream);
}
fclose(f);
return AXIS2_FAILURE;
}
memcpy(byte_stream, temp_byte_stream, temp_byte_stream_size);
memcpy(byte_stream + temp_byte_stream_size, read_stream, count);
if(read_stream)
{
AXIS2_FREE(env->allocator, read_stream);
read_stream_size = 0;
}
if(temp_byte_stream)
{
AXIS2_FREE(env->allocator, temp_byte_stream);
temp_byte_stream = NULL;
temp_byte_stream_size = 0;
}
}
else
{
byte_stream = read_stream;
byte_stream_size = read_stream_size;
read_stream = NULL;
read_stream_size = 0;
}
}
else if(read_stream)
{
AXIS2_FREE(env->allocator, read_stream);
}
}
while(!feof(f));
fclose(f);
data_handler->buffer = byte_stream;
data_handler->buffer_len = byte_stream_size;
*output_stream = byte_stream;
*output_stream_size = byte_stream_size;
}
else if (data_handler->data_handler_type == AXIOM_DATA_HANDLER_TYPE_HANDLER)
{
axis2_byte_t *byte_stream = NULL;
axis2_byte_t *buffer_ptr = NULL;
axis2_byte_t *temp_buffer = NULL;
int byte_stream_size = 0;
int temp_buffer_size = 1;
int total_byte_size = 0;
axiom_mtom_sending_callback_t *callback = NULL;
void *handler_data = NULL;
axis2_status_t status = AXIS2_FAILURE;
if (data_handler->read_handler_create(&callback, env) == AXIS2_FAILURE)
{
return AXIS2_FAILURE;
}
handler_data = AXIOM_MTOM_SENDING_CALLBACK_INIT_HANDLER(callback, env,
data_handler->user_param);
if (handler_data)
{
total_byte_size = AXIOM_MTOM_SENDING_CALLBACK_DATA_SIZE(callback,
env, handler_data);
byte_stream = (axis2_byte_t *)AXIS2_MALLOC(env->allocator,
sizeof(axis2_byte_t) * total_byte_size);
buffer_ptr = byte_stream;
while ((temp_buffer_size > 0) &&
(byte_stream_size < total_byte_size))
{
temp_buffer_size = AXIOM_MTOM_SENDING_CALLBACK_LOAD_DATA(
callback, env, handler_data, &temp_buffer);
if (temp_buffer_size > 0)
{
if ((byte_stream_size + temp_buffer_size) > total_byte_size)
{
temp_buffer_size = total_byte_size - byte_stream_size;
}
memcpy(buffer_ptr, temp_buffer, temp_buffer_size);
buffer_ptr += temp_buffer_size;
byte_stream_size += temp_buffer_size;
AXIS2_FREE(env->allocator, temp_buffer);
}
}
status = AXIOM_MTOM_SENDING_CALLBACK_CLOSE_HANDLER(callback, env,
handler_data);
}
else
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"No data received from handler init function");
status = AXIS2_FAILURE;
}
data_handler->read_handler_remove(callback, env);
if (status == AXIS2_FAILURE)
{
return status;
}
*output_stream = byte_stream;
*output_stream_size = byte_stream_size;
}
else
{
/* unsupported handler type */
return AXIS2_FAILURE;
}
return AXIS2_SUCCESS;
}
AXIS2_EXTERN axis2_status_t AXIS2_CALL
axiom_data_handler_set_binary_data(
axiom_data_handler_t *data_handler,
const axutil_env_t *env,
axis2_byte_t *input_stream,
size_t input_stream_len)
{
data_handler->buffer = input_stream;
data_handler->buffer_len = input_stream_len;
return AXIS2_SUCCESS;
}
/* This function will write the data in the buffer
* to a file. When caching is being used this will
* not be called , because the parser it self cache
* the attachment while parsing */
AXIS2_EXTERN axis2_status_t AXIS2_CALL
axiom_data_handler_write_to(
axiom_data_handler_t *data_handler,
const axutil_env_t *env)
{
if(data_handler->file_name)
{
FILE *f = NULL;
int count = 0;
f = fopen(data_handler->file_name, "wb");
if(!f)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Error opening file %s for writing",
data_handler->file_name);
return AXIS2_FAILURE;
}
count = (int)fwrite(data_handler->buffer, 1, data_handler->buffer_len, f);
/* The count lies within the int range */
if(ferror(f))
{
fclose(f);
return AXIS2_FAILURE;
}
fflush(f);
fclose(f);
}
return AXIS2_SUCCESS;
}
AXIS2_EXTERN axis2_status_t AXIS2_CALL
axiom_data_handler_set_file_name(
axiom_data_handler_t *data_handler,
const axutil_env_t *env,
axis2_char_t *file_name)
{
if(data_handler->file_name)
{
AXIS2_FREE(env->allocator, data_handler->file_name);
data_handler->file_name = NULL;
}
if(file_name)
{
data_handler->file_name = axutil_strdup(env, file_name);
if(!(data_handler->file_name))
{
return AXIS2_FAILURE;
}
}
return AXIS2_SUCCESS;
}
AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axiom_data_handler_get_file_name(
axiom_data_handler_t *data_handler,
const axutil_env_t *env)
{
if(data_handler->file_name)
{
return data_handler->file_name;
}
else
{
return NULL;
}
}
/* This method will add the data_handler binary data to the array_list.
* If it is a buffer the part type is buffer. otherwise it is a file. In the
* case of file the array_list have just the file name and the size. The content
* is not loaded to the memory.
*/
AXIS2_EXTERN axis2_status_t AXIS2_CALL
axiom_data_handler_add_binary_data(
axiom_data_handler_t *data_handler,
const axutil_env_t *env,
axutil_array_list_t *list)
{
axiom_mime_part_t *binary_part = NULL;
binary_part = axiom_mime_part_create(env);
if(!binary_part)
{
return AXIS2_FAILURE;
}
if(data_handler->data_handler_type == AXIOM_DATA_HANDLER_TYPE_BUFFER)
{
binary_part->part = (axis2_byte_t *)AXIS2_MALLOC(env->allocator, (data_handler->buffer_len)
* sizeof(axis2_byte_t));
memcpy(binary_part->part, data_handler->buffer, data_handler->buffer_len);
binary_part->part_size = data_handler->buffer_len;
binary_part->type = AXIOM_MIME_PART_BUFFER;
}
/* In the case of file we first calculate the file size
* and then add the file name */
else if(data_handler->data_handler_type == AXIOM_DATA_HANDLER_TYPE_FILE
&& data_handler->file_name)
{
struct stat stat_p;
if(stat(data_handler->file_name, &stat_p) == -1)
{
return AXIS2_FAILURE;
}
else if(stat_p.st_size == 0)
{
return AXIS2_SUCCESS;
}
else
{
binary_part->file_name = (axis2_char_t *)axutil_strdup(env, data_handler->file_name);
binary_part->part_size = stat_p.st_size;
binary_part->type = AXIOM_MIME_PART_FILE;
}
}
/* In the case where the user has specified some handler functions. Set
* the correct type and pass the handler functions on to the MIME part */
else if(data_handler->data_handler_type == AXIOM_DATA_HANDLER_TYPE_HANDLER)
{
binary_part->type = AXIOM_MIME_PART_HANDLER;
binary_part->user_param = data_handler->user_param;
binary_part->read_handler_create = data_handler->read_handler_create;
binary_part->read_handler_remove = data_handler->read_handler_remove;
}
/* In the case of Callback the user should specify the callback name in the
* configuration file. We just set the correct type. Inside the transport
* it will load the callback and send the attachment appropriately */
else if(data_handler->data_handler_type == AXIOM_DATA_HANDLER_TYPE_CALLBACK)
{
binary_part->type = AXIOM_MIME_PART_CALLBACK;
binary_part->user_param = data_handler->user_param;
}
else
{
/* Data Handler File Name is missing */
return AXIS2_FAILURE;
}
/* Finaly we add the binary details to the list */
axutil_array_list_add(list, env, binary_part);
return AXIS2_SUCCESS;
}
AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axiom_data_handler_get_mime_id(
axiom_data_handler_t *data_handler,
const axutil_env_t *env)
{
return data_handler->mime_id;
}
AXIS2_EXTERN axis2_status_t AXIS2_CALL
axiom_data_handler_set_mime_id(
axiom_data_handler_t *data_handler,
const axutil_env_t *env,
const axis2_char_t *mime_id)
{
if(data_handler->mime_id)
{
AXIS2_FREE(env->allocator, data_handler->mime_id);
}
data_handler->mime_id = axutil_strdup(env, mime_id);
return AXIS2_SUCCESS;
}
AXIS2_EXTERN axiom_data_handler_type_t AXIS2_CALL
axiom_data_handler_get_data_handler_type(
axiom_data_handler_t *data_handler,
const axutil_env_t *env)
{
return data_handler->data_handler_type;
}
AXIS2_EXTERN void AXIS2_CALL
axiom_data_handler_set_data_handler_type(
axiom_data_handler_t *data_handler,
const axutil_env_t *env,
axiom_data_handler_type_t data_handler_type)
{
data_handler->data_handler_type = data_handler_type;
return;
}
AXIS2_EXTERN void AXIS2_CALL
axiom_data_handler_set_read_handler(
axiom_data_handler_t *data_handler,
const axutil_env_t *env,
int (* handler_create)(axiom_mtom_sending_callback_t **, const axutil_env_t *),
int (* handler_remove)(axiom_mtom_sending_callback_t *, const axutil_env_t *))
{
data_handler->read_handler_create = handler_create;
data_handler->read_handler_remove = handler_remove;
}
AXIS2_EXTERN void *AXIS2_CALL
axiom_data_handler_get_user_param(
axiom_data_handler_t *data_handler,
const axutil_env_t *env)
{
return data_handler->user_param;
}
AXIS2_EXTERN void AXIS2_CALL
axiom_data_handler_set_user_param(
axiom_data_handler_t *data_handler,
const axutil_env_t *env,
void *user_param)
{
data_handler->user_param = user_param;
return;
}