| /* |
| * 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_mime_parser.h> |
| #include <axutil_string.h> |
| #include <axiom_data_handler.h> |
| #include <stdio.h> |
| #include <ctype.h> |
| #include <axutil_http_chunked_stream.h> |
| #include <axiom_mtom_caching_callback.h> |
| #include <axutil_class_loader.h> |
| #include <axutil_url.h> |
| |
| struct axiom_mime_parser |
| { |
| /* This will keep the attachment and its info*/ |
| axutil_hash_t *mime_parts_map; |
| |
| /* This is the actual SOAP part len */ |
| size_t soap_body_len; |
| |
| /* The SOAP part of the message */ |
| axis2_char_t *soap_body_str; |
| |
| /* The size of the buffer we give to the callback to |
| * read data */ |
| size_t buffer_size; |
| |
| /* The number of buffers */ |
| int max_buffers; |
| |
| /* The attachment dir name, in the case of caching */ |
| axis2_char_t *attachment_dir; |
| |
| /*A pointer to the caching callback */ |
| axiom_mtom_caching_callback_t *mtom_caching_callback; |
| |
| /* The caching callback name specified */ |
| axis2_char_t *callback_name; |
| |
| axis2_char_t **buf_array; |
| |
| size_t *len_array; |
| |
| int current_buf_num; |
| |
| axis2_bool_t end_of_mime; |
| |
| axis2_char_t *mime_boundary; |
| |
| }; |
| |
| struct axiom_search_info |
| { |
| /*String need to be searched*/ |
| const axis2_char_t *search_str; |
| |
| /*The buffers and the lengths need to be searched*/ |
| axis2_char_t *buffer1; |
| size_t len1; |
| axis2_char_t *buffer2; |
| size_t len2; |
| |
| /*Flag to keep what type of search is this buffer has done*/ |
| axis2_bool_t primary_search; |
| |
| /*The offset where we found the pattern entirely in one buffer*/ |
| size_t match_len1; |
| |
| /*when pattern contains in two buffers the length of partial pattern |
| in buffer2 */ |
| size_t match_len2; |
| |
| /*Whether we need caching or not*/ |
| axis2_bool_t cached; |
| |
| /*A pointer to a user provided storage to which we cache the attachment*/ |
| void *handler; |
| |
| /* Size of the binary when writing to the buffer*/ |
| size_t binary_size; |
| }; |
| |
| typedef struct axiom_search_info axiom_search_info_t; |
| |
| #define AXIOM_MIME_PARSER_CONTENT_ID "content-id" |
| #define AXIOM_MIME_PARSER_CONTENT_TYPE "content-type" |
| |
| #define AXIOM_MIME_PARSER_END_OF_MIME_MAX_COUNT 1000 |
| |
| static axis2_char_t * |
| axiom_mime_parser_search_for_soap( |
| const axutil_env_t * env, |
| AXIS2_READ_INPUT_CALLBACK callback, |
| void *callback_ctx, |
| int *buf_num, |
| size_t *len_array, |
| axis2_char_t **buf_array, |
| axiom_search_info_t *search_info, |
| size_t size, |
| axis2_char_t *mime_boundary, |
| axiom_mime_parser_t *mime_parser); |
| |
| static axis2_char_t * |
| axiom_mime_parser_search_for_crlf( |
| const axutil_env_t * env, |
| AXIS2_READ_INPUT_CALLBACK callback, |
| void *callback_ctx, |
| int *buf_num, |
| size_t *len_array, |
| axis2_char_t **buf_array, |
| axiom_search_info_t *search_info, |
| size_t size, |
| axiom_mime_parser_t *mime_parser); |
| |
| static size_t |
| axiom_mime_parser_calculate_part_len( |
| const axutil_env_t *env, |
| int buf_num, |
| size_t *len_list, |
| int maker, |
| axis2_char_t *pos, |
| axis2_char_t *buf); |
| |
| static axis2_char_t * |
| axiom_mime_parser_create_part( |
| const axutil_env_t *env, |
| size_t part_len, |
| int buf_num, |
| size_t *len_list, |
| int marker, |
| axis2_char_t *pos, |
| axis2_char_t **buf_list, |
| axiom_mime_parser_t *mime_parser); |
| |
| static axis2_char_t * |
| axiom_mime_parser_search_string( |
| axiom_search_info_t *search_info, |
| const axutil_env_t *env); |
| |
| static axis2_char_t * |
| axiom_mime_parser_search_for_attachment( |
| axiom_mime_parser_t *mime_parser, |
| const axutil_env_t * env, |
| AXIS2_READ_INPUT_CALLBACK callback, |
| void *callback_ctx, |
| int *buf_num, |
| size_t *len_array, |
| axis2_char_t **buf_array, |
| axiom_search_info_t *search_info, |
| size_t size, |
| axis2_char_t *mime_boundary, |
| axis2_char_t *mime_id, |
| void *user_param); |
| |
| static axis2_status_t |
| axiom_mime_parser_store_attachment( |
| const axutil_env_t *env, |
| axiom_mime_parser_t *mime_parser, |
| axis2_char_t *mime_id, |
| axis2_char_t *mime_type, |
| axis2_char_t *mime_binary, |
| size_t mime_binary_len, |
| axis2_bool_t cached); |
| |
| static void |
| axiom_mime_parser_clear_buffers( |
| const axutil_env_t *env, |
| axis2_char_t **buf_list, |
| int free_from, |
| int free_to); |
| |
| static axis2_status_t |
| axiom_mime_parser_cache_to_buffer( |
| const axutil_env_t *env, |
| axis2_char_t *buf, |
| size_t buf_len, |
| axiom_search_info_t *search_info, |
| axiom_mime_parser_t *mime_parser); |
| |
| static axis2_bool_t |
| axiom_mime_parser_is_more_data( |
| axiom_mime_parser_t *mime_parser, |
| const axutil_env_t *env, |
| axis2_callback_info_t *callback_info); |
| |
| static axis2_char_t * |
| axiom_mime_parser_process_mime_headers( |
| const axutil_env_t *env, |
| axiom_mime_parser_t *mime_parser, |
| axis2_char_t **mime_id, |
| axis2_char_t *mime_headers); |
| |
| static axis2_status_t |
| axiom_mime_parser_cache_to_file( |
| const axutil_env_t* env, |
| axis2_char_t *buf, |
| size_t buf_len, |
| void *handler); |
| |
| static void* |
| axiom_mime_parser_initiate_callback( |
| axiom_mime_parser_t *mime_parser, |
| const axutil_env_t *env, |
| axis2_char_t *mime_id, |
| void *user_param); |
| |
| AXIS2_EXTERN axiom_mime_parser_t *AXIS2_CALL |
| axiom_mime_parser_create( |
| const axutil_env_t * env) |
| { |
| axiom_mime_parser_t *mime_parser = NULL; |
| |
| AXIS2_ENV_CHECK(env, NULL); |
| mime_parser = (axiom_mime_parser_t *)AXIS2_MALLOC(env->allocator, sizeof(axiom_mime_parser_t)); |
| |
| if(!mime_parser) |
| { |
| AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE); |
| return NULL; |
| } |
| |
| mime_parser->mime_parts_map = NULL; |
| mime_parser->soap_body_len = 0; |
| mime_parser->soap_body_str = NULL; /* shallow copy */ |
| mime_parser->buffer_size = 1; |
| mime_parser->max_buffers = AXIOM_MIME_PARSER_MAX_BUFFERS; |
| mime_parser->attachment_dir = NULL; |
| mime_parser->mtom_caching_callback = NULL; |
| mime_parser->callback_name = NULL; |
| mime_parser->buf_array = NULL; |
| mime_parser->len_array = NULL; |
| mime_parser->current_buf_num = 0; |
| mime_parser->end_of_mime = AXIS2_FALSE; |
| mime_parser->mime_boundary = NULL; |
| |
| mime_parser->mime_parts_map = axutil_hash_make(env); |
| if(!(mime_parser->mime_parts_map)) |
| { |
| axiom_mime_parser_free(mime_parser, env); |
| return NULL; |
| } |
| |
| return mime_parser; |
| } |
| |
| AXIS2_EXTERN void AXIS2_CALL |
| axiom_mime_parser_free( |
| axiom_mime_parser_t * mime_parser, |
| const axutil_env_t * env) |
| { |
| AXIS2_ENV_CHECK(env, AXIS2_FAILURE); |
| |
| /* The map is passed on to SOAP builder, and SOAP builder take over the |
| ownership of the map */ |
| |
| /* We will unload the callback at the end */ |
| |
| if(mime_parser->mtom_caching_callback) |
| { |
| axutil_param_t *param = NULL; |
| param = mime_parser->mtom_caching_callback->param; |
| |
| AXIOM_MTOM_CACHING_CALLBACK_FREE(mime_parser->mtom_caching_callback, env); |
| mime_parser->mtom_caching_callback = NULL; |
| |
| if(param) |
| { |
| axutil_param_free(param, env); |
| param = NULL; |
| } |
| } |
| |
| if(mime_parser->buf_array) |
| { |
| AXIS2_FREE(env->allocator, mime_parser->buf_array); |
| mime_parser->buf_array = NULL; |
| } |
| |
| if(mime_parser->len_array) |
| { |
| AXIS2_FREE(env->allocator, mime_parser->len_array); |
| mime_parser->len_array = NULL; |
| } |
| |
| if(mime_parser->mime_boundary) |
| { |
| AXIS2_FREE(env->allocator, mime_parser->mime_boundary); |
| } |
| |
| if(mime_parser) |
| { |
| AXIS2_FREE(env->allocator, mime_parser); |
| } |
| |
| return; |
| } |
| |
| AXIS2_EXTERN axis2_status_t AXIS2_CALL |
| axiom_mime_parser_parse_for_soap( |
| axiom_mime_parser_t * mime_parser, |
| const axutil_env_t * env, |
| AXIS2_READ_INPUT_CALLBACK callback, |
| void *callback_ctx, |
| axis2_char_t * mime_boundary) |
| { |
| size_t size = 0; |
| axis2_char_t *soap_str = NULL; |
| size_t soap_len = 0; |
| size_t temp_mime_boundary_size = 0; |
| axis2_char_t *temp_mime_boundary = NULL; |
| axis2_char_t **buf_array = NULL; |
| size_t *len_array = NULL; |
| int buf_num = 0; |
| axis2_char_t *pos = NULL; |
| axiom_search_info_t *search_info = NULL; |
| int part_start = 0; |
| axis2_bool_t end_of_mime = AXIS2_FALSE; |
| size_t len = 0; |
| axis2_char_t *buffer = NULL; |
| size_t malloc_len = 0; |
| axis2_callback_info_t *callback_info = NULL; |
| |
| callback_info = (axis2_callback_info_t *)callback_ctx; |
| |
| /* The user will specify the mime_parser->buffer_size */ |
| |
| size = AXIOM_MIME_PARSER_BUFFER_SIZE * (mime_parser->buffer_size); |
| |
| /*An array to keep the set of buffers*/ |
| |
| buf_array = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t *) * (mime_parser->max_buffers)); |
| |
| if(!buf_array) |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "No memory. Failed in creating buffer array"); |
| return AXIS2_FAILURE; |
| } |
| |
| /*Keeps the corresponding lengths of buffers in buf_array*/ |
| |
| len_array = AXIS2_MALLOC(env->allocator, sizeof(size_t) * (mime_parser->max_buffers)); |
| |
| if(!len_array) |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "No memory. Failed in creating length array"); |
| return AXIS2_FAILURE; |
| } |
| |
| mime_parser->buf_array = buf_array; |
| mime_parser->len_array = len_array; |
| |
| temp_mime_boundary = axutil_stracat(env, "--", mime_boundary); |
| temp_mime_boundary_size = strlen(mime_boundary) + 2; |
| |
| /*This struct keeps the pre-post search informations*/ |
| search_info = AXIS2_MALLOC(env->allocator, sizeof(axiom_search_info_t)); |
| |
| /* The first buffer is created */ |
| buf_array[buf_num] = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * (size + 1)); |
| |
| /* The buffer is filled from the callback */ |
| |
| if(buf_array[buf_num]) |
| { |
| len = callback(buf_array[buf_num], (int)size, (void *)callback_ctx); |
| } |
| if(len > 0) |
| { |
| len_array[buf_num] = len; |
| } |
| else |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Error reading from the stream"); |
| return AXIS2_FAILURE; |
| } |
| |
| /*starting buffer for the current search*/ |
| part_start = buf_num; |
| |
| /*We are passing the address of the buf_num , beacause that value |
| is changing inside the method.*/ |
| |
| /* Following call to the method will search first \r\n\r\n */ |
| |
| pos = axiom_mime_parser_search_for_crlf(env, callback, callback_ctx, &buf_num, len_array, |
| buf_array, search_info, size, mime_parser); |
| |
| if(!pos) |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Error in the message."); |
| return AXIS2_FAILURE; |
| } |
| |
| /* The patteren contains in one buffer */ |
| |
| if((search_info->match_len2 == 0)) |
| { |
| /*Readjusting the buffers for the next search and discarding the prevoius |
| buffers*/ |
| |
| /* We need the remaining part in the buffer after the \r\n\r\n*/ |
| |
| malloc_len = buf_array[buf_num] + len_array[buf_num] - pos - 4; |
| if(malloc_len < 0) |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Error in parsing."); |
| return AXIS2_FAILURE; |
| } |
| else |
| { |
| /* Here we will create a new buffer of predefined size fill the |
| * first portion from the remaining part after previous search |
| * and then fill the remaining from the callback */ |
| |
| buffer = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * (size + 1)); |
| |
| if(malloc_len > 0) |
| { |
| memcpy(buffer, pos + 4, malloc_len); |
| } |
| |
| /* Here we need to check for more data, because if the message is too small |
| * comapred to the reading size there may be no data in the stream , instead |
| * all the remaining data may be in the buffer.And if there are no more data |
| * we will set the len to be 0. Otherwise len_array will contain wrong lenghts. |
| */ |
| |
| if(axiom_mime_parser_is_more_data(mime_parser, env, callback_info)) |
| { |
| /* There is more data so fill the remaining from the stream*/ |
| |
| len = callback(buffer + malloc_len, (int)(size - malloc_len), (void *)callback_ctx); |
| } |
| else |
| { |
| len = 0; |
| } |
| |
| /* We do not need the data in the previous buffers once we found a particular |
| * string and after worked with those buffers */ |
| |
| axiom_mime_parser_clear_buffers(env, buf_array, part_start, buf_num); |
| |
| /* Adding the new buffer to the buffer list */ |
| |
| if(len >= 0) |
| { |
| buf_array[buf_num] = buffer; |
| len_array[buf_num] = malloc_len + len; |
| } |
| } |
| } |
| |
| /*The pattern divides among two buffers*/ |
| |
| else if(search_info->match_len2 > 0) |
| { |
| malloc_len = len_array[buf_num] - search_info->match_len2; |
| if(malloc_len < 0) |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Error in parsing."); |
| return AXIS2_FAILURE; |
| } |
| else |
| { |
| buffer = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * (size + 1)); |
| |
| /* Here the buf_num is the second buffer. We will copy the remaining data |
| * after the partial string in the second buffer */ |
| |
| if(malloc_len > 0) |
| { |
| memcpy(buffer, buf_array[buf_num] + search_info->match_len2, malloc_len); |
| } |
| if(axiom_mime_parser_is_more_data(mime_parser, env, callback_info)) |
| { |
| len = callback(buffer + malloc_len, (int)(size - malloc_len), (void *)callback_ctx); |
| } |
| else |
| { |
| len = 0; |
| } |
| axiom_mime_parser_clear_buffers(env, buf_array, part_start, buf_num); |
| if(len >= 0) |
| { |
| buf_array[buf_num] = buffer; |
| len_array[buf_num] = malloc_len + len; |
| } |
| } |
| } |
| else |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Error in parsing."); |
| return AXIS2_FAILURE; |
| } |
| |
| /*Resetting the previous search data and getting ready |
| for the next search */ |
| |
| part_start = buf_num; |
| pos = NULL; |
| malloc_len = 0; |
| |
| search_info->match_len1 = 0; |
| search_info->match_len2 = 0; |
| |
| /*In order to extract the soap envelope we need to search for the first |
| --MIMEBOUNDARY */ |
| |
| pos = axiom_mime_parser_search_for_soap(env, callback, callback_ctx, &buf_num, len_array, |
| buf_array, search_info, size, temp_mime_boundary, mime_parser); |
| |
| if(!pos) |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Error while searching for the SOAP part "); |
| return AXIS2_FAILURE; |
| } |
| |
| if(search_info->match_len2 == 0) |
| { |
| /*Calculating the length of the SOAP str*/ |
| |
| soap_len = axiom_mime_parser_calculate_part_len(env, buf_num, len_array, part_start, pos, |
| buf_array[buf_num]); |
| if(soap_len > 0) |
| { |
| /* Get the SOAP string from the starting and end buffers containing |
| * the SOAP part */ |
| |
| soap_str = axiom_mime_parser_create_part(env, soap_len, buf_num, len_array, part_start, |
| pos, buf_array, mime_parser); |
| if(!soap_str) |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, |
| "Error while creating the SOAP part from the message "); |
| return AXIS2_FAILURE; |
| } |
| |
| malloc_len = len_array[buf_num] - search_info->match_len1 - temp_mime_boundary_size; |
| if(malloc_len < 0) |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Error in parsing for mime."); |
| return AXIS2_FAILURE; |
| } |
| else |
| { |
| /* This will fill the new buffer with remaining data after the |
| * SOAP */ |
| |
| buffer = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * (size + 1)); |
| |
| memset(buffer, 0, size + 1); |
| if(malloc_len > 0) |
| { |
| memcpy(buffer, pos + temp_mime_boundary_size, malloc_len); |
| } |
| if(axiom_mime_parser_is_more_data(mime_parser, env, callback_info)) |
| { |
| len = callback(buffer + malloc_len,(int)(size - malloc_len),(void *)callback_ctx); |
| } |
| else |
| { |
| len = 0; |
| } |
| axiom_mime_parser_clear_buffers(env, buf_array, part_start, buf_num); |
| if(len >= 0) |
| { |
| buf_array[buf_num] = buffer; |
| len_array[buf_num] = malloc_len + len; |
| } |
| } |
| } |
| else |
| { |
| return AXIS2_FAILURE; |
| } |
| } |
| |
| /* This is the condition where the --MIMEBOUNDARY is divided among two |
| * buffers */ |
| |
| else if(search_info->match_len2 > 0) |
| { |
| soap_len = axiom_mime_parser_calculate_part_len(env, buf_num - 1, len_array, part_start, |
| pos, buf_array[buf_num - 1]); |
| |
| if(soap_len > 0) |
| { |
| /* Here we pass buf_num-1 because buf_num does not have any thing we want to |
| * for this particular part. It begins with the latter part of the search string */ |
| |
| soap_str = axiom_mime_parser_create_part(env, soap_len, buf_num - 1, len_array, |
| part_start, pos, buf_array, mime_parser); |
| if(!soap_str) |
| { |
| return AXIS2_FAILURE; |
| } |
| |
| malloc_len = len_array[buf_num] - search_info->match_len2; |
| if(malloc_len < 0) |
| { |
| return AXIS2_FAILURE; |
| } |
| else |
| { |
| buffer = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * (size + 1)); |
| |
| if(malloc_len > 0) |
| { |
| memcpy(buffer, buf_array[buf_num] + search_info->match_len2, malloc_len); |
| } |
| |
| if(axiom_mime_parser_is_more_data(mime_parser, env, callback_info)) |
| { |
| len = callback(buffer + malloc_len,(int)(size - malloc_len),(void *)callback_ctx); |
| } |
| else |
| { |
| len = 0; |
| } |
| axiom_mime_parser_clear_buffers(env, buf_array, part_start, buf_num); |
| if(len >= 0) |
| { |
| buf_array[buf_num] = buffer; |
| len_array[buf_num] = malloc_len + len; |
| } |
| } |
| } |
| else |
| { |
| return AXIS2_FAILURE; |
| } |
| } |
| |
| mime_parser->soap_body_str = soap_str; |
| mime_parser->soap_body_len = soap_len; |
| mime_parser->current_buf_num = buf_num; |
| |
| /* There are multipart/related messages which does not contain attachments |
| * The only mime_part is the soap envelope. So for those messages the mime |
| * boundary after the soap will end up with -- |
| * So we will check that here and if we found then the logic inside the |
| * while loop will not be executed */ |
| |
| end_of_mime = (AXIOM_MIME_BOUNDARY_BYTE == *(buf_array[buf_num])) && (AXIOM_MIME_BOUNDARY_BYTE |
| == *(buf_array[buf_num] + 1)); |
| if(end_of_mime) |
| { |
| AXIS2_FREE(env->allocator, buf_array[buf_num]); |
| buf_array[buf_num] = NULL; |
| } |
| |
| if(temp_mime_boundary) |
| { |
| AXIS2_FREE(env->allocator, temp_mime_boundary); |
| temp_mime_boundary = NULL; |
| } |
| |
| if(search_info) |
| { |
| AXIS2_FREE(env->allocator, search_info); |
| search_info = NULL; |
| } |
| |
| mime_parser->end_of_mime = end_of_mime; |
| |
| return AXIS2_SUCCESS; |
| } |
| |
| AXIS2_EXTERN axutil_hash_t *AXIS2_CALL |
| axiom_mime_parser_parse_for_attachments( |
| axiom_mime_parser_t * mime_parser, |
| const axutil_env_t * env, |
| AXIS2_READ_INPUT_CALLBACK callback, |
| void *callback_ctx, |
| axis2_char_t * mime_boundary, |
| void *user_param) |
| { |
| int count = 0; |
| axiom_search_info_t *search_info = NULL; |
| axis2_char_t *pos = NULL; |
| int part_start = 0; |
| axis2_char_t **buf_array = NULL; |
| size_t *len_array = NULL; |
| int buf_num = 0; |
| size_t size = 0; |
| size_t malloc_len = 0; |
| axis2_callback_info_t *callback_info = NULL; |
| axis2_char_t *temp_mime_boundary = NULL; |
| size_t temp_mime_boundary_size = 0; |
| axis2_bool_t end_of_mime = AXIS2_FALSE; |
| |
| callback_info = (axis2_callback_info_t *)callback_ctx; |
| |
| search_info = AXIS2_MALLOC(env->allocator, sizeof(axiom_search_info_t)); |
| |
| size = AXIOM_MIME_PARSER_BUFFER_SIZE * (mime_parser->buffer_size); |
| |
| buf_array = mime_parser->buf_array; |
| len_array = mime_parser->len_array; |
| buf_num = mime_parser->current_buf_num; |
| |
| /*<SOAP></SOAP>--MIMEBOUNDARY |
| mime_headr1:....... |
| mime_headr2:.... |
| |
| Binarstart................. |
| ...............--MIMEBOUNDARY |
| */ |
| |
| /* This loop will extract all the attachments in the message. The condition |
| * with the count is needed because if the sender not marked the end of the |
| * attachment with -- then this loop may run infinitely. To prevent that |
| * this additional condition has been put */ |
| |
| temp_mime_boundary = axutil_stracat(env, "--", mime_boundary); |
| temp_mime_boundary_size = strlen(mime_boundary) + 2; |
| |
| while((!(mime_parser->end_of_mime)) && count < AXIOM_MIME_PARSER_END_OF_MIME_MAX_COUNT) |
| { |
| /*First we will search for \r\n\r\n*/ |
| axis2_char_t *mime_id = NULL; |
| axis2_char_t *mime_type = NULL; |
| size_t mime_headers_len = 0; |
| size_t mime_binary_len = 0; |
| axis2_char_t *mime_binary = NULL; |
| axis2_char_t *mime_headers = NULL; |
| axis2_char_t *buffer = NULL; |
| int len = 0; |
| axis2_status_t status = AXIS2_FAILURE; |
| |
| search_info->match_len1 = 0; |
| search_info->match_len2 = 0; |
| pos = NULL; |
| part_start = buf_num; |
| |
| malloc_len = 0; |
| |
| count++; |
| |
| pos = axiom_mime_parser_search_for_crlf(env, callback, callback_ctx, &buf_num, len_array, |
| buf_array, search_info, size, mime_parser); |
| |
| if(!pos) |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Error in parsing for mime."); |
| return NULL; |
| } |
| |
| /*The pattern contains in one buffer*/ |
| if(search_info->match_len2 == 0) |
| { |
| /*We found it . so lets seperates the details of this binary into |
| mime headers.*/ |
| |
| mime_headers_len = axiom_mime_parser_calculate_part_len(env, buf_num, len_array, |
| part_start, pos, buf_array[buf_num]); |
| if(mime_headers_len > 0) |
| { |
| mime_headers = axiom_mime_parser_create_part(env, mime_headers_len, buf_num, |
| len_array, part_start, pos, buf_array, mime_parser); |
| |
| if(!mime_headers) |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Error in parsing for mime headers."); |
| return NULL; |
| } |
| malloc_len = buf_array[buf_num] + len_array[buf_num] - pos - 4; |
| |
| /*This should be > 0 , > 0 means there is some part to copy = 0 means |
| there is nothing to copy*/ |
| if(malloc_len < 0) |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Error in parsing for mime headers"); |
| return NULL; |
| } |
| |
| else |
| { |
| buffer = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * (size + 1)); |
| |
| if(malloc_len > 0) |
| { |
| memcpy(buffer, pos + 4, malloc_len); |
| } |
| |
| if(axiom_mime_parser_is_more_data(mime_parser, env, callback_info)) |
| { |
| len = callback(buffer + malloc_len,(int)(size - malloc_len),(void *)callback_ctx); |
| } |
| else |
| { |
| len = 0; |
| } |
| axiom_mime_parser_clear_buffers(env, buf_array, part_start, buf_num); |
| if(len >= 0) |
| { |
| buf_array[buf_num] = buffer; |
| len_array[buf_num] = malloc_len + len; |
| } |
| } |
| } |
| else |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Error in parsing for mime headers."); |
| return NULL; |
| } |
| } |
| |
| else if(search_info->match_len2 > 0) |
| { |
| /*Now we extract the mime headers */ |
| |
| mime_headers_len = axiom_mime_parser_calculate_part_len(env, buf_num - 1, len_array, |
| part_start, pos, buf_array[buf_num - 1]); |
| |
| if(mime_headers_len > 0) |
| { |
| mime_headers = axiom_mime_parser_create_part(env, mime_headers_len, buf_num - 1, |
| len_array, part_start, pos, buf_array, mime_parser); |
| if(!mime_headers) |
| { |
| return NULL; |
| } |
| |
| malloc_len = len_array[buf_num] - search_info->match_len2; |
| if(malloc_len < 0) |
| { |
| return NULL; |
| } |
| else |
| { |
| buffer = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * (size + 1)); |
| |
| if(malloc_len > 0) |
| { |
| memcpy(buffer, buf_array[buf_num] + search_info->match_len2, malloc_len); |
| } |
| if(axiom_mime_parser_is_more_data(mime_parser, env, callback_info)) |
| { |
| len = callback(buffer + malloc_len,(int)(size - malloc_len),(void*)callback_ctx); |
| } |
| else |
| { |
| len = 0; |
| } |
| axiom_mime_parser_clear_buffers(env, buf_array, part_start, buf_num); |
| if(len >= 0) |
| { |
| buf_array[buf_num] = buffer; |
| len_array[buf_num] = malloc_len + len; |
| } |
| } |
| } |
| else |
| { |
| return NULL; |
| } |
| } |
| else |
| { |
| return NULL; |
| } |
| |
| pos = NULL; |
| |
| search_info->match_len1 = 0; |
| search_info->match_len2 = 0; |
| |
| part_start = buf_num; |
| malloc_len = 0; |
| |
| mime_type |
| = axiom_mime_parser_process_mime_headers(env, mime_parser, &mime_id, mime_headers); |
| |
| if(!mime_id) |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, |
| "Error in parsing for mime headers.Mime id did not find"); |
| return NULL; |
| } |
| |
| if(!mime_type) |
| { |
| AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "Mime type did not find"); |
| } |
| |
| /*We extract the mime headers. So lets search for the attachment.*/ |
| |
| pos = axiom_mime_parser_search_for_attachment(mime_parser, env, callback, callback_ctx, |
| &buf_num, len_array, buf_array, search_info, size, temp_mime_boundary, mime_id, |
| user_param); |
| |
| if(pos) |
| { |
| /*If it is small we are not caching. Hence the attachment |
| is in memory. So store it in a buffer. */ |
| |
| if(!search_info->cached) |
| { |
| if(search_info->match_len2 == 0) |
| { |
| /* mime_binary contains the attachment when it does not |
| * cached */ |
| |
| mime_binary_len = axiom_mime_parser_calculate_part_len(env, buf_num, len_array, |
| part_start, pos, buf_array[buf_num]); |
| if(mime_binary_len > 0) |
| { |
| mime_binary = axiom_mime_parser_create_part(env, mime_binary_len, buf_num, |
| len_array, part_start, pos, buf_array, mime_parser); |
| if(!mime_binary) |
| { |
| return NULL; |
| } |
| } |
| else |
| { |
| return NULL; |
| } |
| } |
| |
| else if(search_info->match_len2 > 0) |
| { |
| mime_binary_len = axiom_mime_parser_calculate_part_len(env, buf_num - 1, |
| len_array, part_start, pos, buf_array[buf_num - 1]); |
| |
| if(mime_binary_len > 0) |
| { |
| mime_binary = axiom_mime_parser_create_part(env, mime_binary_len, buf_num |
| - 1, len_array, part_start, pos, buf_array, mime_parser); |
| if(!mime_binary) |
| { |
| return NULL; |
| } |
| } |
| else |
| { |
| return NULL; |
| } |
| } |
| } |
| |
| /* The functionality below is common when it is cached or not. It deals with remaining |
| * after a particualr attachment, Those may be related to a end of mime_boundary or |
| * another attachment */ |
| |
| if(search_info->match_len2 == 0) |
| { |
| malloc_len = len_array[buf_num] - search_info->match_len1 - temp_mime_boundary_size; |
| if(malloc_len < 0) |
| { |
| return NULL; |
| } |
| else |
| { |
| buffer = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * (size + 1)); |
| |
| if(malloc_len > 0) |
| { |
| memcpy(buffer, pos + temp_mime_boundary_size, malloc_len); |
| } |
| |
| /*When the last buffer only containing -- we know this is the end |
| of the attachments. Hence we don't need to read again*/ |
| |
| if(malloc_len != 2) |
| { |
| if(axiom_mime_parser_is_more_data(mime_parser, env, callback_info)) |
| { |
| len = callback(buffer + malloc_len,(int)(size - malloc_len),(void*)callback_ctx); |
| } |
| else |
| { |
| len = 0; |
| } |
| if(len >= 0) |
| { |
| len_array[buf_num] = malloc_len + len; |
| } |
| } |
| |
| /* This means there is another attachment */ |
| else |
| { |
| len_array[buf_num] = malloc_len; |
| } |
| axiom_mime_parser_clear_buffers(env, buf_array, part_start, buf_num); |
| buf_array[buf_num] = buffer; |
| } |
| } |
| else if(search_info->match_len2 > 0) |
| { |
| malloc_len = len_array[buf_num] - search_info->match_len2; |
| |
| if(malloc_len < 0) |
| { |
| return NULL; |
| } |
| else |
| { |
| buffer = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * (size + 1)); |
| |
| if(malloc_len > 0) |
| { |
| memcpy(buffer, buf_array[buf_num] + search_info->match_len2, malloc_len); |
| } |
| if(malloc_len != 2) |
| { |
| if(axiom_mime_parser_is_more_data(mime_parser, env, callback_info)) |
| { |
| len = callback(buffer + malloc_len,(int)(size - malloc_len),(void *)callback_ctx); |
| } |
| else |
| { |
| len = 0; |
| } |
| if(len >= 0) |
| { |
| len_array[buf_num] = malloc_len + len; |
| } |
| } |
| else |
| { |
| len_array[buf_num] = malloc_len; |
| } |
| axiom_mime_parser_clear_buffers(env, buf_array, part_start, buf_num); |
| buf_array[buf_num] = buffer; |
| } |
| } |
| } |
| else |
| { |
| return NULL; |
| } |
| |
| /*We have the attachment now either cached or not. So lets put it in the mime_parts |
| * hash map with the mime_id. Remember at this moment we have already processed the |
| * mime_headers and mime_id is already there */ |
| |
| /* In the case user has not specified the callback or the attachment dir . So we cached it to a memory |
| * buffer. Hence the data_handler type we need to create is different */ |
| |
| if((search_info->cached) && (!mime_parser->attachment_dir) && (!mime_parser->callback_name)) |
| { |
| mime_binary = (axis2_char_t *)search_info->handler; |
| mime_binary_len = search_info->binary_size; |
| } |
| |
| /* Storing the attachment in the hash map with the id*/ |
| |
| status = axiom_mime_parser_store_attachment(env, mime_parser, mime_id, mime_type, |
| mime_binary, mime_binary_len, search_info->cached); |
| |
| /*Check wether we encounter --MIMEBOUNDARY-- to find the end of mime*/ |
| |
| if(buf_array[buf_num]) |
| { |
| /* Here we check for the end of mime */ |
| |
| end_of_mime = (AXIOM_MIME_BOUNDARY_BYTE == *(buf_array[buf_num])) |
| && (AXIOM_MIME_BOUNDARY_BYTE == *(buf_array[buf_num] + 1)); |
| if(end_of_mime) |
| { |
| AXIS2_FREE(env->allocator, buf_array[buf_num]); |
| buf_array[buf_num] = NULL; |
| } |
| mime_parser->end_of_mime = end_of_mime; |
| } |
| |
| if(mime_headers) |
| { |
| AXIS2_FREE(env->allocator, mime_headers); |
| mime_headers = NULL; |
| } |
| |
| if(status != AXIS2_SUCCESS) |
| { |
| return NULL; |
| } |
| } |
| |
| /*Do the necessary cleaning */ |
| |
| /*if (buf_array) |
| { |
| AXIS2_FREE(env->allocator, buf_array); |
| buf_array = NULL; |
| } |
| |
| if (len_array) |
| { |
| AXIS2_FREE(env->allocator, len_array); |
| len_array = NULL; |
| }*/ |
| |
| if(temp_mime_boundary) |
| { |
| AXIS2_FREE(env->allocator, temp_mime_boundary); |
| temp_mime_boundary = NULL; |
| } |
| |
| if(search_info) |
| { |
| AXIS2_FREE(env->allocator, search_info); |
| search_info = NULL; |
| } |
| |
| return mime_parser->mime_parts_map; |
| |
| } |
| |
| /*This method will search for \r\n\r\n */ |
| |
| static axis2_char_t * |
| axiom_mime_parser_search_for_crlf( |
| const axutil_env_t * env, |
| AXIS2_READ_INPUT_CALLBACK callback, |
| void *callback_ctx, |
| int *buf_num, |
| size_t *len_array, |
| axis2_char_t **buf_array, |
| axiom_search_info_t *search_info, |
| size_t size, |
| axiom_mime_parser_t *mime_parser) |
| { |
| axis2_char_t *found = NULL; |
| int len = 0; |
| |
| search_info->search_str = "\r\n\r\n"; |
| search_info->buffer1 = NULL; |
| search_info->buffer2 = NULL; |
| search_info->len1 = 0; |
| search_info->len2 = 0; |
| search_info->match_len1 = 0; |
| search_info->match_len2 = 0; |
| search_info->primary_search = AXIS2_FALSE; |
| search_info->cached = AXIS2_FALSE; |
| search_info->handler = NULL; |
| search_info->binary_size = 0; |
| |
| /*First do a search in the first buffer*/ |
| |
| if(buf_array[*buf_num]) |
| { |
| search_info->buffer1 = buf_array[*buf_num]; |
| search_info->len1 = len_array[*buf_num]; |
| found = axiom_mime_parser_search_string(search_info, env); |
| } |
| |
| while(!found) |
| { |
| /*Let's read another buffer and do a boundary search in both*/ |
| |
| *buf_num = *buf_num + 1; |
| buf_array[*buf_num] = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * (size + 1)); |
| |
| if(buf_array[*buf_num]) |
| { |
| len = callback(buf_array[*buf_num], (int)size, (void *)callback_ctx); |
| } |
| if(len > 0) |
| { |
| len_array[*buf_num] = len; |
| search_info->buffer2 = buf_array[*buf_num]; |
| search_info->len2 = len; |
| found = axiom_mime_parser_search_string(search_info, env); |
| } |
| else |
| { |
| break; |
| } |
| if(!found) |
| { |
| /*Let's do a full search in the second buffer*/ |
| |
| search_info->buffer1 = buf_array[*buf_num]; |
| search_info->len1 = len_array[*buf_num]; |
| search_info->primary_search = AXIS2_FALSE; |
| search_info->buffer2 = NULL; |
| search_info->len2 = 0; |
| found = axiom_mime_parser_search_string(search_info, env); |
| } |
| } |
| |
| return found; |
| } |
| |
| /* This method will search for the mime_boundary after the SOAP part |
| * of the message */ |
| |
| static axis2_char_t * |
| axiom_mime_parser_search_for_soap( |
| const axutil_env_t * env, |
| AXIS2_READ_INPUT_CALLBACK callback, |
| void *callback_ctx, |
| int *buf_num, |
| size_t *len_array, |
| axis2_char_t **buf_array, |
| axiom_search_info_t *search_info, |
| size_t size, |
| axis2_char_t *mime_boundary, |
| axiom_mime_parser_t *mime_parser) |
| { |
| axis2_char_t *found = NULL; |
| int len = 0; |
| |
| /* What we need to search is the mime_boundary */ |
| |
| search_info->search_str = mime_boundary; |
| search_info->buffer1 = NULL; |
| search_info->buffer2 = NULL; |
| search_info->len1 = 0; |
| search_info->len2 = 0; |
| search_info->match_len1 = 0; |
| search_info->match_len2 = 0; |
| search_info->primary_search = AXIS2_FALSE; |
| |
| if(buf_array[*buf_num]) |
| { |
| search_info->buffer1 = buf_array[*buf_num]; |
| search_info->len1 = len_array[*buf_num]; |
| found = axiom_mime_parser_search_string(search_info, env); |
| |
| /* Inside this search primary_search flag will be set to TRUE */ |
| } |
| |
| while(!found) |
| { |
| /* We need to create the second buffer and do the search for the |
| * mime_boundary in the both the buffers */ |
| |
| *buf_num = *buf_num + 1; |
| buf_array[*buf_num] = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * (size + 1)); |
| |
| if(buf_array[*buf_num]) |
| { |
| len = callback(buf_array[*buf_num], (int)size, (void *)callback_ctx); |
| } |
| if(len > 0) |
| { |
| /* In this search we are matching end part of the first |
| * buffer and starting part of the previous buffer */ |
| len_array[*buf_num] = len; |
| search_info->buffer2 = buf_array[*buf_num]; |
| search_info->len2 = len; |
| found = axiom_mime_parser_search_string(search_info, env); |
| } |
| else |
| { |
| break; |
| } |
| if(!found) |
| { |
| search_info->buffer1 = buf_array[*buf_num]; |
| search_info->len1 = len_array[*buf_num]; |
| search_info->primary_search = AXIS2_FALSE; |
| search_info->buffer2 = NULL; |
| search_info->len2 = 0; |
| found = axiom_mime_parser_search_string(search_info, env); |
| } |
| } |
| |
| return found; |
| } |
| |
| /*The caching is done in this function. Caching happens when we did not |
| find the mime_boundary in initial two buffers. So the maximum size |
| that we are keeping in memory is 2 * size. This size can be configurable from |
| the aixs.xml. The caching may starts when the search failed with the |
| second buffer. |
| In this logic first we will search for a callback to cache. If it is not |
| there then we will search for a directory to save the file. If it is also |
| not there then the attachment will be in memory. |
| */ |
| |
| static axis2_char_t * |
| axiom_mime_parser_search_for_attachment( |
| axiom_mime_parser_t *mime_parser, |
| const axutil_env_t * env, |
| AXIS2_READ_INPUT_CALLBACK callback, |
| void *callback_ctx, |
| int *buf_num, |
| size_t *len_array, |
| axis2_char_t **buf_array, |
| axiom_search_info_t *search_info, |
| size_t size, |
| axis2_char_t *mime_boundary, |
| axis2_char_t *mime_id, |
| void *user_param) |
| { |
| axis2_char_t *found = NULL; |
| int len = 0; |
| axis2_status_t status = AXIS2_FAILURE; |
| axis2_char_t *temp = NULL; |
| size_t temp_length = 0; |
| axis2_char_t *file_name = NULL; |
| |
| search_info->search_str = mime_boundary; |
| search_info->buffer1 = NULL; |
| search_info->buffer2 = NULL; |
| search_info->len1 = 0; |
| search_info->len2 = 0; |
| search_info->match_len1 = 0; |
| search_info->match_len2 = 0; |
| search_info->primary_search = AXIS2_FALSE; |
| search_info->cached = AXIS2_FALSE; |
| search_info->handler = NULL; |
| |
| /*First search in the incoming buffer*/ |
| |
| if(buf_array[*buf_num]) |
| { |
| search_info->buffer1 = buf_array[*buf_num]; |
| search_info->len1 = len_array[*buf_num]; |
| found = axiom_mime_parser_search_string(search_info, env); |
| } |
| |
| while(!found) |
| { |
| if(search_info->cached) |
| { |
| if(mime_parser->callback_name) |
| { |
| if(!(search_info->handler)) |
| { |
| /* If the callback is not loaded yet then we load it*/ |
| if(!mime_parser->mtom_caching_callback) |
| { |
| search_info->handler = axiom_mime_parser_initiate_callback(mime_parser, |
| env, mime_id, user_param); |
| if(!(search_info->handler)) |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, |
| "Caching Callback is not loaded"); |
| return NULL; |
| } |
| } |
| } |
| /*So lets cache the previous buffer which has undergone the |
| full search and the partial search. */ |
| |
| if(mime_parser->mtom_caching_callback) |
| { |
| /* Caching callback is loaded. So we can cache the previous buffer */ |
| status |
| = AXIOM_MTOM_CACHING_CALLBACK_CACHE(mime_parser->mtom_caching_callback, |
| env, buf_array[*buf_num - 1], (int)len_array[*buf_num - 1], |
| search_info->handler); |
| } |
| } |
| |
| else if(mime_parser->attachment_dir) |
| { |
| if(!(search_info->handler)) |
| { |
| /* If the File is not opened yet we will open it*/ |
| |
| axis2_char_t *encoded_mime_id = NULL; |
| |
| /* Some times content-ids urls, hence we need to encode them |
| * becasue we can't create files with / */ |
| |
| encoded_mime_id = AXIS2_MALLOC(env->allocator, (sizeof(axis2_char_t)) |
| * (strlen(mime_id))); |
| memset(encoded_mime_id, 0, strlen(mime_id)); |
| encoded_mime_id = axutil_url_encode(env, encoded_mime_id, mime_id, (int)strlen( |
| mime_id)); |
| if(!encoded_mime_id) |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Mime Id encoding failed"); |
| return NULL; |
| } |
| |
| file_name = axutil_stracat(env, mime_parser->attachment_dir, encoded_mime_id); |
| AXIS2_FREE(env->allocator, encoded_mime_id); |
| encoded_mime_id = NULL; |
| |
| if(!file_name) |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Caching file name creation error"); |
| return NULL; |
| } |
| search_info->handler = (void *)fopen(file_name, "ab+"); |
| if(!(search_info->handler)) |
| { |
| return NULL; |
| } |
| } |
| |
| /*So lets cache the previous buffer which has undergone the |
| full search and the partial search. */ |
| |
| status = axiom_mime_parser_cache_to_file(env, buf_array[*buf_num - 1], |
| len_array[*buf_num - 1], search_info->handler); |
| } |
| |
| else |
| { |
| /* Here the user has not specified the caching File location. So we are |
| * not going to cache. Instead we store the attachment in the buffer */ |
| status = axiom_mime_parser_cache_to_buffer(env, buf_array[*buf_num - 1], |
| len_array[*buf_num - 1], search_info, mime_parser); |
| } |
| |
| if(status == AXIS2_FAILURE) |
| { |
| return NULL; |
| } |
| /*Here we interchange the buffers.*/ |
| |
| temp = buf_array[*buf_num - 1]; |
| buf_array[*buf_num - 1] = buf_array[*buf_num]; |
| buf_array[*buf_num] = temp; |
| temp_length = len_array[*buf_num - 1]; |
| len_array[*buf_num - 1] = len_array[*buf_num]; |
| len_array[*buf_num] = temp_length; |
| if(buf_array[*buf_num]) |
| { |
| /*The cached buffer is the one which get filled.*/ |
| len = callback(buf_array[*buf_num], (int)size, (void *)callback_ctx); |
| } |
| } |
| |
| /*Size of the data in memory not yet risen to the caching threasold |
| *So we can create the second buffer */ |
| else |
| { |
| *buf_num = *buf_num + 1; |
| buf_array[*buf_num] = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * (size + 1)); |
| |
| if(buf_array[*buf_num]) |
| { |
| len = callback(buf_array[*buf_num], (int)size, (void *)callback_ctx); |
| } |
| } |
| |
| /*Doing a complete search in newly cretaed buffer*/ |
| |
| if(len > 0) |
| { |
| len_array[*buf_num] = len; |
| search_info->buffer2 = buf_array[*buf_num]; |
| search_info->len2 = len; |
| found = axiom_mime_parser_search_string(search_info, env); |
| } |
| else |
| { |
| break; |
| } |
| |
| /* Now there are two buffers. If the searching string is not |
| * here then we must cache the first buffer */ |
| |
| if(!found) |
| { |
| /*So now we must start caching*/ |
| search_info->buffer1 = buf_array[*buf_num]; |
| search_info->len1 = len_array[*buf_num]; |
| search_info->primary_search = AXIS2_FALSE; |
| search_info->buffer2 = NULL; |
| search_info->len2 = 0; |
| found = axiom_mime_parser_search_string(search_info, env); |
| if(!found) |
| { |
| /* So at the begining of the next search we start |
| * that only after caching this data */ |
| search_info->cached = AXIS2_TRUE; |
| } |
| } |
| } |
| |
| /* Here we are out of the loop. If there is no error then this means |
| * the searching string is found */ |
| if(search_info->cached && found) |
| { |
| /* If the attachment is cached then we need to cache the |
| * final buffer */ |
| |
| if(search_info->match_len2 == 0) |
| { |
| /* This is the case where we found the whole string in one buffer |
| * So we need to cache previous buffer and the data up to the starting |
| * point of the search string in the current buffer */ |
| |
| /* deduct last 2 CRLF character. |
| * For buffering case, it will be done when creating datahandler.*/ |
| |
| if(mime_parser->mtom_caching_callback) |
| { |
| status = AXIOM_MTOM_CACHING_CALLBACK_CACHE(mime_parser->mtom_caching_callback, env, |
| buf_array[*buf_num - 1], (int)len_array[*buf_num - 1], search_info->handler); |
| if(status == AXIS2_SUCCESS) |
| { |
| status |
| = AXIOM_MTOM_CACHING_CALLBACK_CACHE(mime_parser->mtom_caching_callback, |
| env, buf_array[*buf_num], (int)(found - buf_array[*buf_num] - 2), |
| search_info->handler); |
| } |
| } |
| |
| else if(mime_parser->attachment_dir) |
| { |
| status = axiom_mime_parser_cache_to_file(env, buf_array[*buf_num - 1], |
| len_array[*buf_num - 1], search_info->handler); |
| if(status == AXIS2_SUCCESS) |
| { |
| status = axiom_mime_parser_cache_to_file(env, buf_array[*buf_num], found |
| - buf_array[*buf_num] - 2, search_info->handler); |
| } |
| } |
| |
| /* If the callback or a file is not there then the data is appended to the buffer */ |
| |
| else |
| { |
| status = axiom_mime_parser_cache_to_buffer(env, buf_array[*buf_num - 1], |
| len_array[*buf_num - 1], search_info, mime_parser); |
| if(status == AXIS2_SUCCESS) |
| { |
| status = axiom_mime_parser_cache_to_buffer(env, buf_array[*buf_num], found |
| - buf_array[*buf_num], search_info, mime_parser); |
| } |
| } |
| } |
| else if(search_info->match_len2 > 0) |
| { |
| /*Here the curent buffer has partial mime boundary. So we need |
| to cache only the previous buffer. */ |
| |
| if(mime_parser->mtom_caching_callback) |
| { |
| status = AXIOM_MTOM_CACHING_CALLBACK_CACHE(mime_parser->mtom_caching_callback, env, |
| buf_array[*buf_num - 1], (int)(search_info->match_len1 - 2), search_info->handler); |
| } |
| |
| else if(mime_parser->attachment_dir) |
| { |
| status = axiom_mime_parser_cache_to_file(env, buf_array[*buf_num - 1], |
| search_info->match_len1 - 2, search_info->handler); |
| } |
| else |
| { |
| status = axiom_mime_parser_cache_to_buffer(env, buf_array[*buf_num - 1], |
| search_info->match_len1, search_info, mime_parser); |
| } |
| } |
| else |
| { |
| return NULL; |
| } |
| |
| if(status == AXIS2_FAILURE) |
| { |
| return NULL; |
| } |
| } |
| |
| /* Parsing is done so lets close the relative handlers */ |
| |
| if(search_info->handler) |
| { |
| if(mime_parser->mtom_caching_callback) |
| { |
| status = AXIOM_MTOM_CACHING_CALLBACK_CLOSE_HANDLER(mime_parser->mtom_caching_callback, |
| env, search_info->handler); |
| if(status == AXIS2_FAILURE) |
| { |
| return NULL; |
| } |
| } |
| |
| else if(mime_parser->attachment_dir) |
| { |
| if(fclose((FILE *)(search_info->handler)) == 0) |
| { |
| status = AXIS2_SUCCESS; |
| } |
| else |
| { |
| status = AXIS2_FAILURE; |
| } |
| |
| AXIS2_FREE(env->allocator, file_name); |
| file_name = NULL; |
| |
| if(status == AXIS2_FAILURE) |
| { |
| return NULL; |
| } |
| } |
| } |
| return found; |
| } |
| |
| /*following two functions are used to extract important information |
| from the buffer list. eg: SOAP, MIME_HEADERS*/ |
| |
| /*marker is the starting buffer of the required |
| part and pos is the end point of that part */ |
| |
| static size_t |
| axiom_mime_parser_calculate_part_len( |
| const axutil_env_t *env, |
| int buf_num, |
| size_t *len_list, |
| int marker, |
| axis2_char_t *pos, |
| axis2_char_t *buf) |
| { |
| size_t part_len = 0; |
| int i = 0; |
| |
| for(i = marker; i < buf_num; i++) |
| { |
| part_len += len_list[i]; |
| } |
| |
| part_len = part_len + (pos - buf); |
| |
| return part_len; |
| } |
| |
| static axis2_char_t * |
| axiom_mime_parser_create_part( |
| const axutil_env_t *env, |
| size_t part_len, |
| int buf_num, |
| size_t *len_list, |
| int marker, |
| axis2_char_t *pos, |
| axis2_char_t **buf_list, |
| axiom_mime_parser_t *mime_parser) |
| { |
| /*We will copy the set of buffers which contains the required part. |
| This part can be the SOAP message , mime headers or the mime |
| binary in the case of none cahced.*/ |
| |
| axis2_char_t *part_str = NULL; |
| int i = 0; |
| size_t temp = 0; |
| |
| part_str = AXIS2_MALLOC(env->allocator, sizeof(char) * (part_len + 1)); |
| |
| if(!part_str) |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "No memory. Failed in creating buffer"); |
| return NULL; |
| } |
| |
| /* Copy from the part starting buffer to the |
| * curent buffer */ |
| |
| for(i = marker; i < buf_num; i++) |
| { |
| if(buf_list[i]) |
| { |
| memcpy(part_str + temp, buf_list[i], len_list[i]); |
| temp += len_list[i]; |
| } |
| } |
| /* Finally we are copying from the final portion */ |
| |
| memcpy(part_str + temp, buf_list[i], pos - buf_list[i]); |
| |
| part_str[part_len] = '\0'; |
| |
| return part_str; |
| } |
| |
| AXIS2_EXTERN axutil_hash_t *AXIS2_CALL |
| axiom_mime_parser_get_mime_parts_map( |
| axiom_mime_parser_t * mime_parser, |
| const axutil_env_t * env) |
| { |
| return mime_parser->mime_parts_map; |
| } |
| |
| AXIS2_EXTERN size_t AXIS2_CALL |
| axiom_mime_parser_get_soap_body_len( |
| axiom_mime_parser_t * mime_parser, |
| const axutil_env_t * env) |
| { |
| return mime_parser->soap_body_len; |
| } |
| |
| AXIS2_EXTERN axis2_char_t *AXIS2_CALL |
| axiom_mime_parser_get_soap_body_str( |
| axiom_mime_parser_t * mime_parser, |
| const axutil_env_t * env) |
| { |
| return mime_parser->soap_body_str; |
| } |
| |
| /*This is the new search function. This will first do a |
| search for the entire search string.Then will do a search |
| for the partial string which can be divided among two buffers.*/ |
| |
| static axis2_char_t * |
| axiom_mime_parser_search_string( |
| axiom_search_info_t *search_info, |
| const axutil_env_t *env) |
| { |
| axis2_char_t *pos = NULL; |
| axis2_char_t *old_pos = NULL; |
| axis2_char_t *found = NULL; |
| size_t str_length = 0; |
| size_t search_length = 0; |
| |
| str_length = strlen(search_info->search_str); |
| |
| /*First lets search the entire buffer*/ |
| if(!search_info->primary_search) |
| { |
| old_pos = search_info->buffer1; |
| |
| do |
| { |
| /*find the first byte. We need to adhere to this |
| approach rather than straightaway using strstr |
| because the buffer1 can be containg binary data*/ |
| |
| pos = NULL; |
| |
| search_length = search_info->buffer1 + search_info->len1 - old_pos - str_length + 1; |
| |
| if(search_length < 0) |
| { |
| break; |
| } |
| |
| if(old_pos) |
| { |
| pos = memchr(old_pos, *(search_info->search_str), search_length); |
| } |
| |
| /* found it so lets check the remaining */ |
| |
| if(pos) |
| { |
| found = axutil_strstr(pos, search_info->search_str); |
| if(found) |
| { |
| search_info->match_len1 = found - search_info->buffer1; |
| break; |
| } |
| else |
| { |
| old_pos = pos + 1; |
| } |
| } |
| } |
| while(pos); |
| } |
| |
| search_info->primary_search = AXIS2_TRUE; |
| |
| if(found) |
| { |
| return found; |
| } |
| |
| /*So we didn't find the string in the buffer |
| lets check whether it is divided in two buffers*/ |
| |
| else |
| { |
| size_t offset = 0; |
| pos = NULL; |
| old_pos = NULL; |
| found = NULL; |
| search_length = 0; |
| |
| if(search_info->buffer2) |
| { |
| old_pos = search_info->buffer1 + search_info->len1 - str_length + 1; |
| do |
| { |
| /*First check the starting byte*/ |
| pos = NULL; |
| found = NULL; |
| |
| search_length = search_info->buffer1 + search_info->len1 - old_pos; |
| |
| if(search_length < 0) |
| { |
| break; |
| } |
| |
| pos = memchr(old_pos, *(search_info->search_str), search_length); |
| |
| if(pos) |
| { |
| offset = search_info->buffer1 + search_info->len1 - pos; |
| |
| /*First match the beginng to offset in buffer1*/ |
| |
| if(offset > 0) |
| { |
| if(memcmp(pos, search_info->search_str, offset) == 0) |
| { |
| found = pos; |
| } |
| |
| /*We found something in buffer1 so lets match the |
| remaining in buffer2*/ |
| |
| if(found) |
| { |
| if(memcmp(search_info->buffer2, search_info->search_str + offset, |
| str_length - offset) == 0) |
| { |
| search_info->match_len2 = str_length - offset; |
| search_info->match_len1 = found - search_info->buffer1; |
| break; |
| } |
| else |
| { |
| old_pos = pos + 1; |
| } |
| } |
| else |
| { |
| old_pos = pos + 1; |
| } |
| } |
| } |
| } |
| while(pos); |
| |
| /* We will set this to AXIS2_FALSE so when the next time this |
| * search method is called it will do a full search first for buffer1 */ |
| search_info->primary_search = AXIS2_FALSE; |
| |
| return found; |
| } |
| else |
| { |
| return NULL; |
| } |
| } |
| } |
| |
| /* This method creates a data_handler out of the attachment |
| * and store the data_handler in the mime_parts map */ |
| |
| static axis2_status_t |
| axiom_mime_parser_store_attachment( |
| const axutil_env_t *env, |
| axiom_mime_parser_t *mime_parser, |
| axis2_char_t *mime_id, |
| axis2_char_t *mime_type, |
| axis2_char_t *mime_binary, |
| size_t mime_binary_len, |
| axis2_bool_t cached) |
| { |
| if(mime_parser->mime_parts_map) |
| { |
| if(mime_id) |
| { |
| axiom_data_handler_t *data_handler = NULL; |
| |
| /* Handling the case where attachment is cached using a callback */ |
| |
| if(mime_parser->callback_name && cached) |
| { |
| data_handler = axiom_data_handler_create(env, NULL, mime_type); |
| if(data_handler) |
| { |
| axiom_data_handler_set_cached(data_handler, env, AXIS2_TRUE); |
| axiom_data_handler_set_data_handler_type(data_handler, env, |
| AXIOM_DATA_HANDLER_TYPE_CALLBACK); |
| } |
| } |
| |
| /* Handling the case where attachment is cached to a file*/ |
| |
| else if(mime_parser->attachment_dir && cached) |
| { |
| axis2_char_t *attachment_location = NULL; |
| axis2_char_t *encoded_mime_id = NULL; |
| |
| /* Some times content-ids urls, hence we need to encode them |
| * becasue we can't create files with / */ |
| |
| encoded_mime_id = AXIS2_MALLOC(env->allocator, (sizeof(axis2_char_t)) * (strlen( |
| mime_id))); |
| memset(encoded_mime_id, 0, strlen(mime_id)); |
| encoded_mime_id = axutil_url_encode( |
| env, encoded_mime_id, mime_id, (int)strlen(mime_id)); |
| if(!encoded_mime_id) |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Mime Id encoding failed"); |
| return AXIS2_FAILURE; |
| } |
| |
| attachment_location = axutil_stracat(env, mime_parser->attachment_dir, |
| encoded_mime_id); |
| |
| AXIS2_FREE(env->allocator, encoded_mime_id); |
| encoded_mime_id = NULL; |
| |
| if(attachment_location) |
| { |
| |
| data_handler = axiom_data_handler_create(env, attachment_location, mime_type); |
| if(data_handler) |
| { |
| axiom_data_handler_set_cached(data_handler, env, AXIS2_TRUE); |
| |
| } |
| AXIS2_FREE(env->allocator, attachment_location); |
| attachment_location = NULL; |
| } |
| } |
| |
| /* Attachment is in memory, either it is small to be cached or |
| * user does not provided the attachment cached directory */ |
| |
| else if(mime_binary) |
| { |
| data_handler = axiom_data_handler_create(env, NULL, mime_type); |
| if(data_handler) |
| { |
| axiom_data_handler_set_binary_data(data_handler, env, mime_binary, |
| mime_binary_len - 2); |
| } |
| } |
| axiom_data_handler_set_mime_id(data_handler, env, mime_id); |
| |
| axutil_hash_set(mime_parser->mime_parts_map, mime_id, AXIS2_HASH_KEY_STRING, |
| data_handler); |
| if(mime_type) |
| { |
| AXIS2_FREE(env->allocator, mime_type); |
| } |
| } |
| else |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Mime Id or Mime rype not found"); |
| return AXIS2_FAILURE; |
| /*axis2_char_t temp_boundry[1024]; |
| sprintf(temp_boundry, "--%s--", mime_boundary); |
| if (body_mime && axutil_strstr(body_mime, temp_boundry)) |
| { |
| break; |
| }*/ |
| } |
| return AXIS2_SUCCESS; |
| } |
| else |
| { |
| return AXIS2_FAILURE; |
| } |
| } |
| |
| /* This method will process the mime_headers for a particualr |
| attacment and return the mime_id */ |
| |
| static axis2_char_t * |
| axiom_mime_parser_process_mime_headers( |
| const axutil_env_t *env, |
| axiom_mime_parser_t *mime_parser, |
| axis2_char_t **mime_id, |
| axis2_char_t *mime_headers) |
| { |
| axis2_char_t *id = NULL; |
| axis2_char_t *type = NULL; |
| axis2_char_t *pos = NULL; |
| |
| /* Get the MIME ID */ |
| if(mime_headers) |
| { |
| id = axutil_strcasestr(mime_headers, AXIOM_MIME_HEADER_CONTENT_ID); |
| type = axutil_strcasestr(mime_headers, AXIOM_MIME_HEADER_CONTENT_TYPE); |
| if(type) |
| { |
| axis2_char_t *end = NULL; |
| axis2_char_t *temp_type = NULL; |
| type += axutil_strlen(AXIOM_MIME_HEADER_CONTENT_TYPE); |
| while(type && *type && *type != ':') |
| { |
| type++; |
| } |
| type++; |
| while(type && *type && *type == ' ') |
| { |
| type++; |
| } |
| end = type; |
| while(end && *end && !isspace((int)*end)) |
| { |
| end++; |
| } |
| if((end - type) > 0) |
| { |
| temp_type = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * ((end - type) + 1)); |
| if(!temp_type) |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, |
| "No memory. Failed in creating Content-Type"); |
| return NULL; |
| } |
| memcpy(temp_type, type, (end - type)); |
| temp_type[end - type] = '\0'; |
| type = temp_type; |
| } |
| } |
| if(id) |
| { |
| id += axutil_strlen(AXIOM_MIME_HEADER_CONTENT_ID); |
| while(id && *id && *id != ':') |
| { |
| id++; |
| } |
| if(id) |
| { |
| while(id && *id && *id != '<') |
| { |
| id++; |
| } |
| id++; |
| pos = axutil_strstr(id, ">"); |
| if(pos) |
| { |
| int mime_id_len = 0; |
| mime_id_len = (int)(pos - id); |
| *mime_id = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * mime_id_len + 1); |
| /* The MIME ID will be freed by the SOAP builder */ |
| if(*mime_id) |
| { |
| memcpy(*mime_id, id, mime_id_len); |
| (*mime_id)[mime_id_len] = '\0'; |
| } |
| else |
| { |
| AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, |
| "No memory. Failed in creating MIME ID"); |
| return NULL; |
| } |
| } |
| } |
| } |
| else |
| { |
| /*axis2_char_t temp_boundry[1024]; |
| sprintf(temp_boundry, "--%s--", mime_boundary); |
| if (body_mime && axutil_strstr(body_mime, temp_boundry)) |
| { |
| break; |
| }*/ |
| return NULL; |
| } |
| return type; |
| } |
| else |
| { |
| return NULL; |
| } |
| } |
| |
| /*This is used to free some unwanted buffers. For example we did |
| not want the buffers which contains the data before the soap |
| envelope starts. */ |
| |
| static void |
| axiom_mime_parser_clear_buffers( |
| const axutil_env_t *env, |
| axis2_char_t **buf_list, |
| int free_from, |
| int free_to) |
| { |
| int i = 0; |
| |
| for(i = free_from; i <= free_to; i++) |
| { |
| if(buf_list[i]) |
| { |
| AXIS2_FREE(env->allocator, buf_list[i]); |
| buf_list[i] = NULL; |
| } |
| } |
| return; |
| } |
| |
| /* Instead of caching to a file this method will cache it |
| * to a buffer */ |
| |
| static axis2_status_t |
| axiom_mime_parser_cache_to_buffer( |
| const axutil_env_t *env, |
| axis2_char_t *buf, |
| size_t buf_len, |
| axiom_search_info_t *search_info, |
| axiom_mime_parser_t *mime_parser) |
| { |
| axis2_char_t *data_buffer = NULL; |
| axis2_char_t *temp_buf = NULL; |
| size_t mime_binary_len = 0; |
| |
| temp_buf = (axis2_char_t *)search_info->handler; |
| mime_binary_len = search_info->binary_size + buf_len; |
| |
| if(mime_binary_len > 0) |
| { |
| data_buffer = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * (mime_binary_len)); |
| |
| if(data_buffer) |
| { |
| if(temp_buf && search_info->binary_size > 0) |
| { |
| memcpy(data_buffer, temp_buf, search_info->binary_size); |
| AXIS2_FREE(env->allocator, temp_buf); |
| temp_buf = NULL; |
| } |
| memcpy(data_buffer + (search_info->binary_size), buf, buf_len); |
| search_info->binary_size = mime_binary_len; |
| search_info->handler = (void *)data_buffer; |
| |
| return AXIS2_SUCCESS; |
| } |
| else |
| { |
| return AXIS2_FAILURE; |
| } |
| } |
| else |
| { |
| return AXIS2_FAILURE; |
| } |
| } |
| |
| AXIS2_EXTERN void AXIS2_CALL |
| axiom_mime_parser_set_buffer_size( |
| axiom_mime_parser_t *mime_parser, |
| const axutil_env_t *env, |
| int size) |
| { |
| mime_parser->buffer_size = size; |
| } |
| |
| AXIS2_EXTERN void AXIS2_CALL |
| axiom_mime_parser_set_max_buffers( |
| axiom_mime_parser_t *mime_parser, |
| const axutil_env_t *env, |
| int num) |
| { |
| mime_parser->max_buffers = num; |
| } |
| |
| AXIS2_EXTERN void AXIS2_CALL |
| axiom_mime_parser_set_attachment_dir( |
| axiom_mime_parser_t *mime_parser, |
| const axutil_env_t *env, |
| axis2_char_t *attachment_dir) |
| { |
| mime_parser->attachment_dir = attachment_dir; |
| } |
| |
| /* Set the path of the caching callnack to be loaded */ |
| |
| AXIS2_EXTERN void AXIS2_CALL |
| axiom_mime_parser_set_caching_callback_name( |
| axiom_mime_parser_t *mime_parser, |
| const axutil_env_t *env, |
| axis2_char_t *callback_name) |
| { |
| mime_parser->callback_name = callback_name; |
| } |
| |
| AXIS2_EXTERN void AXIS2_CALL |
| axiom_mime_parser_set_mime_boundary( |
| axiom_mime_parser_t *mime_parser, |
| const axutil_env_t *env, |
| axis2_char_t *mime_boundary) |
| { |
| mime_parser->mime_boundary = mime_boundary; |
| } |
| |
| AXIS2_EXTERN axis2_char_t *AXIS2_CALL |
| axiom_mime_parser_get_mime_boundary( |
| axiom_mime_parser_t *mime_parser, |
| const axutil_env_t *env) |
| { |
| return mime_parser->mime_boundary; |
| } |
| |
| /* Load the caching callback dll */ |
| |
| static void* |
| axiom_mime_parser_initiate_callback( |
| axiom_mime_parser_t *mime_parser, |
| const axutil_env_t *env, |
| axis2_char_t *mime_id, |
| void *user_param) |
| { |
| axutil_dll_desc_t *dll_desc = NULL; |
| axutil_param_t *impl_info_param = NULL; |
| void *ptr = NULL; |
| |
| if(mime_parser->callback_name) |
| { |
| AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "Trying to load module = %s", |
| mime_parser->callback_name); |
| dll_desc = axutil_dll_desc_create(env); |
| axutil_dll_desc_set_name(dll_desc, env, mime_parser->callback_name); |
| impl_info_param = axutil_param_create(env, NULL, dll_desc); |
| /*Set the free function*/ |
| 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. ERROR", |
| mime_parser->callback_name); |
| return NULL; |
| } |
| |
| mime_parser->mtom_caching_callback = (axiom_mtom_caching_callback_t *)ptr; |
| mime_parser->mtom_caching_callback->param = impl_info_param; |
| mime_parser->mtom_caching_callback->user_param = user_param; |
| |
| return AXIOM_MTOM_CACHING_CALLBACK_INIT_HANDLER(mime_parser->mtom_caching_callback, env, |
| mime_id); |
| } |
| |
| else |
| { |
| return NULL; |
| } |
| |
| } |
| |
| /* This method will tell whether there are more data in the |
| * stream */ |
| |
| static axis2_bool_t |
| axiom_mime_parser_is_more_data( |
| axiom_mime_parser_t *mime_parser, |
| const axutil_env_t *env, |
| axis2_callback_info_t *callback_info) |
| { |
| /* In the case of axutil_http_chunked stream it is the |
| * end of chunk */ |
| |
| if(callback_info->chunked_stream) |
| { |
| if(axutil_http_chunked_stream_get_end_of_chunks(callback_info->chunked_stream, env)) |
| { |
| return AXIS2_FALSE; |
| } |
| else |
| { |
| return AXIS2_TRUE; |
| } |
| } |
| |
| /* When we are using content length or any wrapped |
| * stream it will be the unread_length */ |
| |
| else if(callback_info->unread_len == 0) |
| { |
| return AXIS2_FALSE; |
| } |
| else |
| { |
| return AXIS2_TRUE; |
| } |
| } |
| |
| static axis2_status_t |
| axiom_mime_parser_cache_to_file( |
| const axutil_env_t* env, |
| axis2_char_t *buf, |
| size_t buf_len, |
| void *handler) |
| { |
| size_t len = 0; |
| FILE *fp = NULL; |
| |
| fp = (FILE *)handler; |
| |
| len = fwrite(buf, 1, buf_len, fp); |
| if(len < 0) |
| { |
| return AXIS2_FAILURE; |
| } |
| else |
| { |
| return AXIS2_SUCCESS; |
| } |
| } |
| |