/* * 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 #include #include #include 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; }