diff options
author | gmcdonald | 2010-02-13 01:32:03 +0000 |
---|---|---|
committer | gmcdonald | 2010-02-13 01:32:03 +0000 |
commit | 0425aadc78680e53000fd0108b540d6eca048516 (patch) | |
tree | 8ec7ab8e015d454c5ec586dfc91e05a2dce1cfc0 /src/core/transport/http/sender/libcurl | |
download | axis2c-0425aadc78680e53000fd0108b540d6eca048516.tar.gz axis2c-0425aadc78680e53000fd0108b540d6eca048516.tar.bz2 |
Moving axis svn, part of TLP move INFRA-2441
git-svn-id: http://svn.apache.org/repos/asf/axis/axis2/c/core/trunk@909681 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/core/transport/http/sender/libcurl')
5 files changed, 1467 insertions, 0 deletions
diff --git a/src/core/transport/http/sender/libcurl/Makefile.am b/src/core/transport/http/sender/libcurl/Makefile.am new file mode 100644 index 0000000..90e5ce6 --- /dev/null +++ b/src/core/transport/http/sender/libcurl/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST= axis2_libcurl.h axis2_libcurl.c libcurl_stream.h libcurl_stream.c + diff --git a/src/core/transport/http/sender/libcurl/axis2_libcurl.c b/src/core/transport/http/sender/libcurl/axis2_libcurl.c new file mode 100644 index 0000000..834e69b --- /dev/null +++ b/src/core/transport/http/sender/libcurl/axis2_libcurl.c @@ -0,0 +1,1169 @@ +/* + * 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. + */ +#ifdef AXIS2_LIBCURL_ENABLED + +#include "axis2_libcurl.h" +#include <axiom_soap.h> +#include <axutil_string.h> +#include <axis2_http_transport.h> +#include <axiom_output.h> +#include <axis2_op_ctx.h> +#include <axis2_ctx.h> +#include <axis2_conf_ctx.h> +#include <axis2_http_client.h> +#include <axiom_xml_writer.h> +#include <axutil_property.h> +#include <axutil_param.h> +#include <axutil_types.h> +#include <axutil_generic_obj.h> +#include <axis2_const.h> +#include <axis2_util.h> +#include <stdlib.h> +#include <axis2_http_sender.h> +#include <axis2_http_transport.h> +#include "libcurl_stream.h" + +static int ref = 0; + +struct axis2_libcurl +{ + axis2_char_t *memory; + axutil_array_list_t *alist; + unsigned int size; + const axutil_env_t *env; + char errorbuffer[CURL_ERROR_SIZE]; + CURL *handler; + axis2_bool_t cookies; +}; + +static size_t +axis2_libcurl_write_memory_callback( + void *ptr, + size_t size, + size_t nmemb, + void *data); + +static size_t +axis2_libcurl_header_callback( + void *ptr, + size_t size, + size_t nmemb, + void *data); + +static axis2_char_t * +axis2_libcurl_get_content_type( + axis2_libcurl_t *curl, + const axutil_env_t * env); + +static int +axis2_libcurl_get_content_length( + axis2_libcurl_t *curl, + const axutil_env_t * env); + +static axis2_http_header_t * +axis2_libcurl_get_first_header( + axis2_libcurl_t *curl, + const axutil_env_t * env, + const axis2_char_t * str); + +static void +axis2_libcurl_free_headers( + axis2_libcurl_t *curl, + const axutil_env_t * env); + +static axis2_status_t +axis2_libcurl_set_options( + CURL *handler, + const axutil_env_t * env, + axis2_msg_ctx_t * msg_ctx); + +axis2_status_t AXIS2_CALL +axis2_libcurl_send( + axis2_libcurl_t *data, + axiom_output_t * om_output, + const axutil_env_t * env, + axis2_msg_ctx_t * msg_ctx, + axiom_soap_envelope_t * out, + const axis2_char_t * str_url, + const axis2_char_t * soap_action) +{ + struct curl_slist *headers = NULL; + axiom_soap_body_t *soap_body; + axis2_bool_t is_soap = AXIS2_TRUE; + axis2_bool_t send_via_get = AXIS2_FALSE; + axis2_bool_t send_via_head = AXIS2_FALSE; + axis2_bool_t send_via_put = AXIS2_FALSE; + axis2_bool_t send_via_delete = AXIS2_FALSE; + axis2_bool_t doing_mtom = AXIS2_FALSE; + axiom_node_t *body_node = NULL; + axiom_node_t *data_out = NULL; + axutil_property_t *method = NULL; + axis2_char_t *method_value = NULL; + axiom_xml_writer_t *xml_writer = NULL; + axis2_char_t *buffer = NULL; + unsigned int buffer_size = 0; + int content_length = -1; + axis2_char_t *content_type = NULL; + axis2_char_t *content_len = AXIS2_HTTP_HEADER_CONTENT_LENGTH_; + const axis2_char_t *char_set_enc = NULL; + axis2_char_t *content = AXIS2_HTTP_HEADER_CONTENT_TYPE_; + axis2_char_t *soap_action_header = AXIS2_HTTP_HEADER_SOAP_ACTION_; + axutil_stream_t *in_stream; + axutil_property_t *trans_in_property; + axutil_string_t *char_set_enc_str; + axis2_byte_t *output_stream = NULL; + int output_stream_size = 0; + CURL *handler; + axis2_conf_ctx_t *conf_ctx = NULL; + axis2_conf_t *conf = NULL; + axis2_transport_out_desc_t *trans_desc = NULL; + axutil_param_t *write_xml_declaration_param = NULL; + axutil_hash_t *transport_attrs = NULL; + axis2_bool_t write_xml_declaration = AXIS2_FALSE; + axutil_property_t *property; + int *response_length = NULL; + axis2_http_status_line_t *status_line = NULL; + axis2_char_t *status_line_str = NULL; + axis2_char_t *tmp_strcat = NULL; + int status_code = 0; + + AXIS2_PARAM_CHECK(env->error, data, AXIS2_FAILURE); + AXIS2_PARAM_CHECK(env->error, data->handler, AXIS2_FAILURE); + + handler = data->handler; + curl_easy_reset(handler); + curl_easy_setopt(handler, CURLOPT_ERRORBUFFER, &data->errorbuffer); + headers = curl_slist_append(headers, AXIS2_HTTP_HEADER_USER_AGENT_AXIS2C); + headers = curl_slist_append(headers, AXIS2_HTTP_HEADER_ACCEPT_); + headers = curl_slist_append(headers, AXIS2_HTTP_HEADER_EXPECT_); + + if(AXIS2_FAILURE == axis2_libcurl_set_options(handler, env, msg_ctx)) + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "[axis2libcurl]Setting options in Libcurl failed"); + return AXIS2_FAILURE; + } + + if (AXIS2_TRUE == axis2_msg_ctx_get_doing_rest(msg_ctx, env)) + { + is_soap = AXIS2_FALSE; + } + else + { + is_soap = AXIS2_TRUE; + } + + if (!is_soap) + { + soap_body = axiom_soap_envelope_get_body(out, env); + if (!soap_body) + { + AXIS2_HANDLE_ERROR(env, + AXIS2_ERROR_SOAP_ENVELOPE_OR_SOAP_BODY_NULL, + AXIS2_FAILURE); + return AXIS2_FAILURE; + } + + body_node = axiom_soap_body_get_base_node(soap_body, env); + if (!body_node) + { + AXIS2_HANDLE_ERROR(env, + AXIS2_ERROR_SOAP_ENVELOPE_OR_SOAP_BODY_NULL, + AXIS2_FAILURE); + + return AXIS2_FAILURE; + } + data_out = axiom_node_get_first_element(body_node, env); + + method = (axutil_property_t *) axis2_msg_ctx_get_property(msg_ctx, env, + AXIS2_HTTP_METHOD); + + if (method) + { + method_value = + (axis2_char_t *) axutil_property_get_value(method, env); + } + + /* The default is POST */ + if (method_value && 0 == axutil_strcmp(method_value, AXIS2_HTTP_GET)) + { + send_via_get = AXIS2_TRUE; + } + else if (method_value && 0 == axutil_strcmp(method_value, AXIS2_HTTP_HEAD)) + { + send_via_head = AXIS2_TRUE; + } + else if (method_value && 0 == axutil_strcmp(method_value, AXIS2_HTTP_PUT)) + { + send_via_put = AXIS2_TRUE; + } + else if (method_value && 0 == axutil_strcmp(method_value, AXIS2_HTTP_DELETE)) + { + send_via_delete = AXIS2_TRUE; + } + } + + conf_ctx = axis2_msg_ctx_get_conf_ctx (msg_ctx, env); + if (conf_ctx) + { + conf = axis2_conf_ctx_get_conf (conf_ctx, env); + } + + if (conf) + { + trans_desc = axis2_conf_get_transport_out (conf, + env, AXIS2_TRANSPORT_ENUM_HTTP); + } + + if (trans_desc) + { + write_xml_declaration_param = + axutil_param_container_get_param + (axis2_transport_out_desc_param_container (trans_desc, env), env, + AXIS2_XML_DECLARATION); + } + + if (write_xml_declaration_param) + { + transport_attrs = + axutil_param_get_attributes (write_xml_declaration_param, env); + if (transport_attrs) + { + axutil_generic_obj_t *obj = NULL; + axiom_attribute_t *write_xml_declaration_attr = NULL; + axis2_char_t *write_xml_declaration_attr_value = NULL; + + obj = axutil_hash_get (transport_attrs, AXIS2_ADD_XML_DECLARATION, + AXIS2_HASH_KEY_STRING); + if (obj) + { + write_xml_declaration_attr = (axiom_attribute_t *) + axutil_generic_obj_get_value (obj, + env); + } + if (write_xml_declaration_attr) + { + write_xml_declaration_attr_value = + axiom_attribute_get_value (write_xml_declaration_attr, env); + } + if (write_xml_declaration_attr_value && + 0 == axutil_strcasecmp (write_xml_declaration_attr_value, + AXIS2_VALUE_TRUE)) + { + write_xml_declaration = AXIS2_TRUE; + } + } + } + + if (write_xml_declaration) + { + axiom_output_write_xml_version_encoding (om_output, env); + } + + if (!send_via_get && !send_via_head && !send_via_delete) + { + xml_writer = axiom_output_get_xml_writer(om_output, env); + + char_set_enc_str = axis2_msg_ctx_get_charset_encoding(msg_ctx, env); + + if (!char_set_enc_str) + { + char_set_enc = AXIS2_DEFAULT_CHAR_SET_ENCODING; + } + else + { + char_set_enc = axutil_string_get_buffer(char_set_enc_str, env); + } + + if (!send_via_put && is_soap) + { + doing_mtom = axis2_msg_ctx_get_doing_mtom(msg_ctx, env); + + axiom_output_set_do_optimize(om_output, env, doing_mtom); + axiom_soap_envelope_serialize(out, env, om_output, AXIS2_FALSE); + if (AXIS2_TRUE == axis2_msg_ctx_get_is_soap_11(msg_ctx, env)) + { + if (AXIS2_ESC_DOUBLE_QUOTE != *soap_action) + { + axis2_char_t *tmp_soap_action = NULL; + tmp_soap_action = + AXIS2_MALLOC(env->allocator, + (axutil_strlen(soap_action) + + 5) * sizeof(axis2_char_t)); + sprintf(tmp_soap_action, "\"%s\"", soap_action); + tmp_strcat = axutil_stracat(env, soap_action_header,tmp_soap_action); + headers = curl_slist_append(headers, tmp_strcat); + AXIS2_FREE(env->allocator, tmp_strcat); + AXIS2_FREE(env->allocator, tmp_soap_action); + } + else + { + tmp_strcat = axutil_stracat(env, soap_action_header, soap_action); + headers = curl_slist_append(headers, tmp_strcat ); + AXIS2_FREE(env->allocator, tmp_strcat); + } + } + + if (doing_mtom) + { + /*axiom_output_flush(om_output, env, &output_stream, + &output_stream_size);*/ + axiom_output_flush(om_output, env); + content_type = + (axis2_char_t *) axiom_output_get_content_type(om_output, + env); + if (AXIS2_TRUE != axis2_msg_ctx_get_is_soap_11(msg_ctx, env)) + { + if (axutil_strcmp(soap_action, "")) + { + /* handle SOAP action for SOAP 1.2 case */ + axis2_char_t *temp_content_type = NULL; + temp_content_type = axutil_stracat (env, + content_type, + AXIS2_CONTENT_TYPE_ACTION); + content_type = temp_content_type; + temp_content_type = axutil_stracat (env, + content_type, + soap_action); + AXIS2_FREE (env->allocator, content_type); + content_type = temp_content_type; + temp_content_type = + axutil_stracat (env, content_type, + AXIS2_ESC_DOUBLE_QUOTE_STR); + AXIS2_FREE (env->allocator, content_type); + content_type = temp_content_type; + } + } + } + else if (AXIS2_TRUE == axis2_msg_ctx_get_is_soap_11(msg_ctx, env)) + { + axis2_char_t *temp_content_type = NULL; + content_type = + (axis2_char_t *) AXIS2_HTTP_HEADER_ACCEPT_TEXT_XML; + content_type = axutil_stracat(env, content_type, + AXIS2_CONTENT_TYPE_CHARSET); + temp_content_type = + axutil_stracat(env, content_type, char_set_enc); + AXIS2_FREE(env->allocator, content_type); + content_type = temp_content_type; + } + else + { + axis2_char_t *temp_content_type = NULL; + content_type = + (axis2_char_t *) AXIS2_HTTP_HEADER_ACCEPT_APPL_SOAP; + content_type = axutil_stracat(env, content_type, + AXIS2_CONTENT_TYPE_CHARSET); + temp_content_type = + axutil_stracat(env, content_type, char_set_enc); + AXIS2_FREE(env->allocator, content_type); + content_type = temp_content_type; + if (axutil_strcmp(soap_action, "")) + { + temp_content_type = + axutil_stracat(env, content_type, + AXIS2_CONTENT_TYPE_ACTION); + AXIS2_FREE(env->allocator, content_type); + content_type = temp_content_type; + temp_content_type = + axutil_stracat(env, content_type, soap_action); + AXIS2_FREE(env->allocator, content_type); + content_type = temp_content_type; + } + temp_content_type = axutil_stracat(env, content_type, + AXIS2_SEMI_COLON_STR); + AXIS2_FREE(env->allocator, content_type); + content_type = temp_content_type; + } + } + else if (is_soap) + { + AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Attempt to send SOAP" + "message using HTTP PUT failed"); + return AXIS2_FAILURE; + } + else + { + axutil_property_t *content_type_property = NULL; + axutil_hash_t *content_type_hash = NULL; + axis2_char_t *content_type_value = NULL; + + axiom_node_serialize(data_out, env, om_output); + content_type_property = + (axutil_property_t *) + axis2_msg_ctx_get_property(msg_ctx, env, + AXIS2_USER_DEFINED_HTTP_HEADER_CONTENT_TYPE); + + if (content_type_property) + { + content_type_hash = + (axutil_hash_t *) + axutil_property_get_value(content_type_property, env); + + if (content_type_hash) + { + content_type_value = + (char *) axutil_hash_get(content_type_hash, + AXIS2_HTTP_HEADER_CONTENT_TYPE, + AXIS2_HASH_KEY_STRING); + } + } + + if (content_type_value) + { + content_type = content_type_value; + } + else + { + content_type = AXIS2_HTTP_HEADER_ACCEPT_TEXT_XML; + } + + } + + buffer = axiom_xml_writer_get_xml(xml_writer, env); + if (!doing_mtom) + { + buffer_size = axiom_xml_writer_get_xml_size(xml_writer, env); + } + else + buffer_size = output_stream_size; + { + char tmp_buf[10]; + sprintf(tmp_buf, "%d", buffer_size); + tmp_strcat = axutil_stracat(env, content_len, tmp_buf); + headers = curl_slist_append(headers, tmp_strcat); + AXIS2_FREE(env->allocator, tmp_strcat); + tmp_strcat = NULL; + + tmp_strcat = axutil_stracat(env, content, content_type); + headers = curl_slist_append(headers, tmp_strcat); + AXIS2_FREE(env->allocator, tmp_strcat); + tmp_strcat = NULL; + } + + if (!doing_mtom) + { + curl_easy_setopt(handler, CURLOPT_POSTFIELDSIZE, buffer_size); + curl_easy_setopt(handler, CURLOPT_POSTFIELDS, buffer); + } + else + { + curl_easy_setopt(handler, CURLOPT_POSTFIELDSIZE, + output_stream_size); + curl_easy_setopt(handler, CURLOPT_POSTFIELDS, output_stream); + } + + if (send_via_put) + { + curl_easy_setopt(handler, CURLOPT_CUSTOMREQUEST, AXIS2_HTTP_PUT); + } + curl_easy_setopt(handler, CURLOPT_URL, str_url); + } + else + { + axis2_char_t *request_param; + axis2_char_t *url_encode; + request_param = + (axis2_char_t *) axis2_http_sender_get_param_string(NULL, env, + msg_ctx); + url_encode = axutil_strcat(env, str_url, AXIS2_Q_MARK_STR, + request_param, NULL); + if (send_via_get) + { + curl_easy_setopt(handler, CURLOPT_HTTPGET, 1); + } + else if (send_via_head) + { + curl_easy_setopt(handler, CURLOPT_NOBODY, 1); + } + else if (send_via_delete) + { + curl_easy_setopt(handler, CURLOPT_CUSTOMREQUEST, AXIS2_HTTP_DELETE); + } + curl_easy_setopt(handler, CURLOPT_URL, url_encode); + } + + { + axis2_bool_t manage_session; + manage_session = axis2_msg_ctx_get_manage_session(msg_ctx, env); + if (manage_session == AXIS2_TRUE) + { + if (data->cookies == AXIS2_FALSE) + { + /* Ensure cookies enabled to manage session */ + /* Pass empty cookie string to enable cookies */ + curl_easy_setopt(handler, CURLOPT_COOKIEFILE, " "); + data->cookies = AXIS2_TRUE; + } + } + else if (data->cookies == AXIS2_TRUE) + { + /* Pass special string ALL to reset cookies if any have been enabled. */ + /* If cookies have ever been enabled, we reset every time as long as + manage_session is false, as there is no clear curl option to + turn off the cookie engine once enabled. */ + curl_easy_setopt(handler, CURLOPT_COOKIELIST, AXIS2_ALL); + } + } + + curl_easy_setopt(handler, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(handler, CURLOPT_WRITEFUNCTION, + axis2_libcurl_write_memory_callback); + curl_easy_setopt(handler, CURLOPT_WRITEDATA, data); + + curl_easy_setopt (handler, CURLOPT_HEADERFUNCTION, axis2_libcurl_header_callback); + + curl_easy_setopt (handler, CURLOPT_WRITEHEADER, data); + + /* Free response data from previous request */ + if( data->size ) + { + if (data->memory) + { + AXIS2_FREE(data->env->allocator, data->memory); + } + data->size = 0; + } + + if (curl_easy_perform(handler)) + { + AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "%s", &data->errorbuffer); + AXIS2_HANDLE_ERROR(env, AXIS2_ERROR_HTTP_CLIENT_TRANSPORT_ERROR, + AXIS2_FAILURE); + return AXIS2_FAILURE; + } + + in_stream = axutil_stream_create_libcurl(env, data->memory, data->size); + trans_in_property = axutil_property_create(env); + axutil_property_set_scope(trans_in_property, env, AXIS2_SCOPE_REQUEST); + axutil_property_set_free_func(trans_in_property, env, + libcurl_stream_free); + axutil_property_set_value(trans_in_property, env, in_stream); + axis2_msg_ctx_set_property(msg_ctx, env, AXIS2_TRANSPORT_IN, + trans_in_property); + + if (axutil_array_list_size(data->alist, env) > 0) + { + status_line_str = axutil_array_list_get(data->alist, env, 0); + if (status_line_str) + { + status_line = axis2_http_status_line_create(env, status_line_str); + } + } + + if (status_line) + { + status_code = axis2_http_status_line_get_status_code(status_line, env); + } + + axis2_msg_ctx_set_status_code (msg_ctx, env, status_code); + AXIS2_FREE(data->env->allocator, content_type); + content_type = axis2_libcurl_get_content_type(data, env); + + if (content_type) + { + if (strstr (content_type, AXIS2_HTTP_HEADER_ACCEPT_MULTIPART_RELATED) + && strstr (content_type, AXIS2_HTTP_HEADER_ACCEPT_XOP_XML)) + { + axis2_ctx_t *axis_ctx = + axis2_op_ctx_get_base (axis2_msg_ctx_get_op_ctx (msg_ctx, env), + env); + property = axutil_property_create (env); + axutil_property_set_scope (property, env, AXIS2_SCOPE_REQUEST); + axutil_property_set_value (property, + env, axutil_strdup (env, content_type)); + axis2_ctx_set_property (axis_ctx, + env, MTOM_RECIVED_CONTENT_TYPE, property); + } + } + + content_length = axis2_libcurl_get_content_length(data, env); + if (content_length >= 0) + { + response_length = AXIS2_MALLOC (env->allocator, sizeof (int)); + memcpy (response_length, &content_length, sizeof (int)); + property = axutil_property_create (env); + axutil_property_set_scope (property, env, AXIS2_SCOPE_REQUEST); + axutil_property_set_value (property, env, response_length); + axis2_msg_ctx_set_property (msg_ctx, env, + AXIS2_HTTP_HEADER_CONTENT_LENGTH, property); + } + + curl_slist_free_all (headers); + /* release the read http headers. */ + /* (commenting out the call below is a clever way to force a premature EOF + condition in subsequent messages, as they will be read using the content-length + of the first message.) */ + axis2_libcurl_free_headers(data, env); + AXIS2_FREE(data->env->allocator, content_type); + axis2_http_status_line_free( status_line, env); + + return AXIS2_SUCCESS; +} + +static size_t +axis2_libcurl_write_memory_callback( + void *ptr, + size_t size, + size_t nmemb, + void *data) +{ + size_t realsize = size * nmemb; + axis2_libcurl_t *curl = (axis2_libcurl_t *) data; + axis2_char_t *buffer = + (axis2_char_t *) AXIS2_MALLOC(curl->env->allocator, + curl->size + realsize + 1); + if (buffer) + { + if (curl->size) + { + memcpy(&(buffer[0]), curl->memory, curl->size); + AXIS2_FREE(curl->env->allocator, curl->memory); + } + + memcpy(&(buffer[curl->size]), ptr, realsize); + curl->size += (int)realsize; + /* We are sure that the difference lies within the int range */ + buffer[curl->size] = 0; + curl->memory = buffer; + } + return realsize; +} + +static size_t +axis2_libcurl_header_callback( + void *ptr, + size_t size, + size_t nmemb, + void *data) +{ + axis2_char_t *memory; + size_t realsize = size * nmemb; + axis2_libcurl_t *curl = (axis2_libcurl_t *) data; + memory = (axis2_char_t *)AXIS2_MALLOC(curl->env->allocator, realsize + 1); + if (memory) + { + memcpy(&(memory[0]), ptr, realsize); + memory[realsize] = 0; + axutil_array_list_add(curl->alist, curl->env, memory); + } + return realsize; +} + +axis2_libcurl_t * AXIS2_CALL +axis2_libcurl_create( + const axutil_env_t * env) +{ + axis2_libcurl_t *curl = NULL; + CURLcode code; + + if (!ref) + { + /* curl_global_init is not thread-safe so it would be better + to do this, as well as the test and increment of ref, under + mutex if one is available, or as part of an + axis2_initialize() if a global initialize is created. + Otherwise the client application should perform the the + curl_global_init itself in a thread-safe fashion. + */ + code = curl_global_init(CURL_GLOBAL_ALL); + if (code) + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, + "libcurl curl_global_init failed, error: %d", code); + return NULL; + } + ref++; + } + + curl = + (axis2_libcurl_t *) AXIS2_MALLOC(env->allocator, + sizeof(axis2_libcurl_t)); + if (curl) + { + curl->memory = 0; + curl->size = 0; + curl->alist = axutil_array_list_create(env, 15); + curl->env = env; + curl->handler = curl_easy_init(); + curl->cookies = AXIS2_FALSE; + if ((!curl->alist) || (!curl->handler)) + { + axis2_libcurl_free(curl, env); + curl = 0; + } + } + return curl; +} + +void AXIS2_CALL +axis2_libcurl_free( + axis2_libcurl_t *curl, + const axutil_env_t * env) +{ + if (!curl) + { + return; + } + + if (curl->handler) + { + curl_easy_cleanup (curl->handler); + } + if (curl->alist) + { + axis2_libcurl_free_headers(curl, env); + axutil_array_list_free(curl->alist, env); + curl->alist = NULL; + } + if (curl->memory) + { + AXIS2_FREE(env->allocator, curl->memory); + } + + AXIS2_FREE(env->allocator, curl); +} + +static void +axis2_libcurl_free_headers( + axis2_libcurl_t *curl, + const axutil_env_t * env) +{ + int count = 0; + axutil_array_list_t *header_group = curl->alist; + if (header_group) + { + while ((count = axutil_array_list_size(header_group, env)) > 0) + { + axis2_char_t *header = axutil_array_list_remove(header_group, env, count-1); + AXIS2_FREE(env->allocator, header); + } + } +} + +static axis2_http_header_t * +axis2_libcurl_get_first_header( + axis2_libcurl_t *curl, + const axutil_env_t * env, + const axis2_char_t * str) +{ + axis2_http_header_t *tmp_header = NULL; + axis2_char_t *tmp_header_str = NULL; + axis2_char_t *tmp_name = NULL; + int i = 0; + int count = 0; + axutil_array_list_t *header_group = NULL; + + AXIS2_PARAM_CHECK(env->error, curl, NULL); + AXIS2_PARAM_CHECK(env->error, str, NULL); + + header_group = curl->alist; + if (!header_group) + { + return NULL; + } + + if (0 == axutil_array_list_size(header_group, env)) + { + return NULL; + } + + count = axutil_array_list_size(header_group, env); + + for (i = 0; i < count; i++) + { + tmp_header_str = (axis2_char_t *) axutil_array_list_get(header_group, + env, i); + if(!tmp_header_str) + { + continue; + } + tmp_header = (axis2_http_header_t *) axis2_http_header_create_by_str(env, tmp_header_str); + if(!tmp_header) + { + continue; + } + + tmp_name = axis2_http_header_get_name(tmp_header, env); + if (0 == axutil_strcasecmp(str, tmp_name)) + { + return tmp_header; + } + else + { + axis2_http_header_free( tmp_header, env ); + } + + } + return NULL; +} + +static int +axis2_libcurl_get_content_length( + axis2_libcurl_t *curl, + const axutil_env_t * env) +{ + axis2_http_header_t *tmp_header; + int rtn_value = -1; + + tmp_header = axis2_libcurl_get_first_header + (curl, env, AXIS2_HTTP_HEADER_CONTENT_LENGTH); + if (tmp_header) + { + rtn_value = AXIS2_ATOI(axis2_http_header_get_value(tmp_header, env)); + axis2_http_header_free( tmp_header, env ); + } + return rtn_value; +} + +static axis2_char_t * +axis2_libcurl_get_content_type( + axis2_libcurl_t *curl, + const axutil_env_t * env) +{ + axis2_http_header_t *tmp_header; + axis2_char_t *rtn_value = NULL; + + tmp_header = axis2_libcurl_get_first_header + (curl, env, AXIS2_HTTP_HEADER_CONTENT_TYPE); + if (tmp_header) + { + rtn_value = axutil_strdup (env, axis2_http_header_get_value(tmp_header, env) ); + axis2_http_header_free( tmp_header, env ); + } + else + { + rtn_value = axutil_strdup (env, AXIS2_HTTP_HEADER_ACCEPT_TEXT_PLAIN); + } + + return rtn_value; +} + +/** + * axis2_libcurl_set_auth_options maps authentication AXIS2/C options to + * libcURL options. + * + * CURLOPT_USERPWD - char * user:password for authentication + * CURLOPT_HTTPAUTH - long bitmask which authentication methods to use + */ +static axis2_status_t +axis2_libcurl_set_auth_options( + CURL *handler, + const axutil_env_t * env, + axis2_msg_ctx_t * msg_ctx) +{ + axutil_property_t *property = NULL; + axis2_char_t *uname = NULL; + axis2_char_t *passwd = NULL; + axis2_char_t *auth_type = NULL; + + property = axis2_msg_ctx_get_property(msg_ctx, env, AXIS2_HTTP_AUTH_UNAME); + if (property) + { + uname = (axis2_char_t *) axutil_property_get_value(property, env); + } + property = axis2_msg_ctx_get_property(msg_ctx, env, AXIS2_HTTP_AUTH_PASSWD); + if (property) + { + passwd = (axis2_char_t *) axutil_property_get_value(property, env); + } + if (uname && passwd) + { + axis2_char_t buffer[256]; + strncpy(buffer, uname, 256); + strncat(buffer, ":", 256); + strncat(buffer, passwd, 256); + curl_easy_setopt(handler, CURLOPT_USERPWD, buffer); + } + + property = (axutil_property_t *)axis2_msg_ctx_get_property(msg_ctx, env, AXIS2_HTTP_AUTH_TYPE); + + if (property) + { + auth_type = (axis2_char_t *) axutil_property_get_value(property, env); + } + + if (auth_type && 0 == axutil_strcmp(auth_type, AXIS2_HTTP_AUTH_TYPE_BASIC)) + { + curl_easy_setopt(handler, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + } + else + { + /* Uses anonymous connection.*/ + } + + return AXIS2_SUCCESS; +} + +/** + * axis2_libcurl_set_proxy_options maps proxy AXIS2/C options to + * libcURL options. + * + * CURLOPT_PROXY - char * proxy hostname + * CURLOPT_PROXYPORT - long proxy listen port + * CURLOPT_PROXYUSERPWD - char * user:password to authenticate to proxy + * + * TODO: + * CURLOPT_PROXYTYPE - long enum type of proxy (HTTP, SOCKS) + * CURLOPT_PROXYAUTH - long bitmask which authentication methods to use for proxy + */ +static axis2_status_t +axis2_libcurl_set_proxy_options( + CURL *handler, + const axutil_env_t * env, + axis2_msg_ctx_t * msg_ctx) +{ + axis2_conf_ctx_t *conf_ctx = NULL; + axis2_conf_t *conf = NULL; + axis2_transport_out_desc_t *trans_desc = NULL; + axutil_param_t *proxy_param = NULL; + axutil_hash_t *transport_attrs = NULL; + axutil_property_t *property = NULL; + axis2_char_t *uname = NULL; + axis2_char_t *passwd = NULL; + axis2_char_t *proxy_host = NULL; + axis2_char_t *proxy_port = NULL; + + property = axis2_msg_ctx_get_property(msg_ctx, env, AXIS2_PROXY_AUTH_UNAME); + if (property) + { + uname = (axis2_char_t *) axutil_property_get_value(property, env); + } + property = axis2_msg_ctx_get_property(msg_ctx, env, AXIS2_PROXY_AUTH_PASSWD); + if (property) + { + passwd = (axis2_char_t *) axutil_property_get_value(property, env); + } + + conf_ctx = axis2_msg_ctx_get_conf_ctx(msg_ctx, env); + if (conf_ctx) + { + conf = axis2_conf_ctx_get_conf(conf_ctx, env); + if (conf) + { + trans_desc = axis2_conf_get_transport_out(conf, env, AXIS2_TRANSPORT_ENUM_HTTP); + } + } + if (trans_desc) + { + proxy_param = axutil_param_container_get_param( + axis2_transport_out_desc_param_container(trans_desc, env), env, AXIS2_HTTP_PROXY_API); + if (!proxy_param) + { + proxy_param = axutil_param_container_get_param( + axis2_transport_out_desc_param_container(trans_desc, env), env, AXIS2_HTTP_PROXY); + } + if (proxy_param) + { + transport_attrs = axutil_param_get_attributes(proxy_param, env); + } + } + + if (transport_attrs) + { + axutil_generic_obj_t *obj = NULL; + axiom_attribute_t *attr = NULL; + + if (!uname || !passwd) + { + obj = axutil_hash_get(transport_attrs, AXIS2_HTTP_PROXY_USERNAME, AXIS2_HASH_KEY_STRING); + if (obj) + { + attr = (axiom_attribute_t *) axutil_generic_obj_get_value(obj, env); + } + if (attr) + { + uname = axiom_attribute_get_value(attr, env); + } + + attr = NULL; + obj = axutil_hash_get(transport_attrs, AXIS2_HTTP_PROXY_PASSWORD, AXIS2_HASH_KEY_STRING); + if (obj) + { + attr = (axiom_attribute_t *)axutil_generic_obj_get_value(obj, env); + } + if (attr) + { + passwd = axiom_attribute_get_value(attr, env); + } + } + + obj = axutil_hash_get(transport_attrs, AXIS2_HTTP_PROXY_HOST, AXIS2_HASH_KEY_STRING); + if (obj) + { + attr = (axiom_attribute_t *)axutil_generic_obj_get_value(obj, env); + } + if (attr) + { + proxy_host = axiom_attribute_get_value(attr, env); + } + if (proxy_host) + { + curl_easy_setopt(handler, CURLOPT_PROXY, proxy_host); + } + + attr = NULL; + obj = axutil_hash_get(transport_attrs, AXIS2_HTTP_PROXY_PORT, AXIS2_HASH_KEY_STRING); + if (obj) + { + attr = (axiom_attribute_t *)axutil_generic_obj_get_value(obj, env); + } + if (attr) + { + proxy_port = axiom_attribute_get_value(attr, env); + } + if (proxy_port) + { + curl_easy_setopt(handler, CURLOPT_PROXYPORT, AXIS2_ATOI(proxy_port)); + } + } + if (uname && passwd) + { + axis2_char_t buffer[256]; + strncpy(buffer, uname, 256); + strncat(buffer, ":", 256); + strncat(buffer, passwd, 256); + curl_easy_setopt(handler, CURLOPT_PROXYUSERPWD, buffer); + } + + return AXIS2_SUCCESS; +} + +/** + * axis2_libcurl_set_ssl_options maps SSL AXIS2/C options to + * libcURL options. + * + * CURLOPT_SSL_VERIFYHOST - long enum whether to verify the server identity + * CURLOPT_SSL_VERIFYPEER - long boolean whether to verify the server certificate + */ +static axis2_status_t +axis2_libcurl_set_ssl_options( + CURL *handler, + const axutil_env_t * env, + axis2_msg_ctx_t * msg_ctx) +{ + axutil_property_t *property = NULL; + axis2_char_t *verify_peer = NULL; + axis2_char_t *verify_host = NULL; + + property = axis2_msg_ctx_get_property(msg_ctx, env, AXIS2_SSL_VERIFY_PEER); + if (property) + { + verify_peer = (axis2_char_t *)axutil_property_get_value(property, env); + } + if (verify_peer) + { + if (0 == axutil_strcasecmp(verify_peer, AXIS2_VALUE_TRUE)) + { + curl_easy_setopt(handler, CURLOPT_SSL_VERIFYPEER, 1); + } + else + { + curl_easy_setopt(handler, CURLOPT_SSL_VERIFYPEER, 0); + } + } + + property = axis2_msg_ctx_get_property(msg_ctx, env, AXIS2_SSL_VERIFY_HOST); + if (property) + { + verify_host = (axis2_char_t *)axutil_property_get_value(property, env); + } + if (verify_host) + { + curl_easy_setopt(handler, CURLOPT_SSL_VERIFYHOST, AXIS2_ATOI(verify_host)); + } + + return AXIS2_SUCCESS; +} + +/** + * axis2_libcurl_set_connection_options maps connection AXIS2/C options to + * libcURL options. + * CURLOPT_CONNECTTIMEOUT_MS - long connection timeout in milliseconds + * CURLOPT_TIMEOUT_MS - long transfer timeout in milliseconds + */ +static axis2_status_t +axis2_libcurl_set_connection_options( + CURL *handler, + const axutil_env_t * env, + axis2_msg_ctx_t * msg_ctx) +{ + axutil_property_t *property = NULL; + long long_property_value = 0; + + /* check if timeout has been set by user using options + * with axis2_options_set_timeout_in_milli_seconds + */ + property = axis2_msg_ctx_get_property(msg_ctx, env, AXIS2_HTTP_CONNECTION_TIMEOUT); + if (property) + { + axis2_char_t *value = axutil_property_get_value(property, env); + if (value) + { + long_property_value = AXIS2_ATOI(value); + curl_easy_setopt(handler, CURLOPT_CONNECTTIMEOUT_MS, long_property_value); + } + } + + property = axis2_msg_ctx_get_property(msg_ctx, env, AXIS2_HTTP_SO_TIMEOUT); + if (property) + { + axis2_char_t *value = axutil_property_get_value(property, env); + if (value) + { + long_property_value = AXIS2_ATOI(value); + curl_easy_setopt(handler, CURLOPT_TIMEOUT_MS, long_property_value); + } + } + + return AXIS2_SUCCESS; +} + +/** + * axis2_libcurl_set_options maps the AXIS2/C options to libcURL options. + */ +static axis2_status_t +axis2_libcurl_set_options( + CURL *handler, + const axutil_env_t * env, + axis2_msg_ctx_t * msg_ctx) +{ + if (axis2_libcurl_set_auth_options(handler, env, msg_ctx) != AXIS2_SUCCESS) + { + return AXIS2_FAILURE; + } + + if (axis2_libcurl_set_proxy_options(handler, env, msg_ctx) != AXIS2_SUCCESS) + { + return AXIS2_FAILURE; + } + + if (axis2_libcurl_set_ssl_options(handler, env, msg_ctx) != AXIS2_SUCCESS) + { + return AXIS2_FAILURE; + } + + if (axis2_libcurl_set_connection_options(handler, env, msg_ctx) != AXIS2_SUCCESS) + { + return AXIS2_FAILURE; + } + + return AXIS2_SUCCESS; +} + + +#endif /* AXIS2_LIBCURL_ENABLED */ + diff --git a/src/core/transport/http/sender/libcurl/axis2_libcurl.h b/src/core/transport/http/sender/libcurl/axis2_libcurl.h new file mode 100644 index 0000000..f2971e5 --- /dev/null +++ b/src/core/transport/http/sender/libcurl/axis2_libcurl.h @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#ifndef AXIS2_LIBCURL_H +#define AXIS2_LIBCURL_H +#include <curl/curl.h> +#include <stdio.h> +#include <string.h> +#include <axis2_http_sender.h> +#include <axutil_string.h> +#include <axutil_types.h> +#include <axutil_generic_obj.h> +#include <axis2_const.h> +#include <axis2_util.h> +#include <axiom.h> + +/* typedef struct axis2_libcurl axis2_libcurl_t; */ +/* actually defined in axis2_http_sender.h as it is part of axis2/include */ + +AXIS2_EXTERN axis2_libcurl_t *AXIS2_CALL +axis2_libcurl_create( + const axutil_env_t * env); + +AXIS2_EXTERN void AXIS2_CALL +axis2_libcurl_free( + axis2_libcurl_t *data, + const axutil_env_t * env); + +AXIS2_EXTERN axis2_status_t AXIS2_CALL +axis2_libcurl_send( + axis2_libcurl_t *data, + axiom_output_t * om_output, + const axutil_env_t * env, + axis2_msg_ctx_t * msg_ctx, + axiom_soap_envelope_t * out, + const axis2_char_t * str_url, + const axis2_char_t * soap_action); + +#endif /* AXIS2_LIBCURL_H */ diff --git a/src/core/transport/http/sender/libcurl/libcurl_stream.c b/src/core/transport/http/sender/libcurl/libcurl_stream.c new file mode 100644 index 0000000..0c9126d --- /dev/null +++ b/src/core/transport/http/sender/libcurl/libcurl_stream.c @@ -0,0 +1,192 @@ +/* + * 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. + */ +#ifdef AXIS2_LIBCURL_ENABLED + +#include "libcurl_stream.h" +#include <string.h> + +typedef struct libcurl_stream_impl +{ + axutil_stream_t stream; + axutil_stream_type_t stream_type; + axis2_char_t *buffer; + int size; + int read_len; +} +libcurl_stream_impl_t; + +#define AXIS2_INTF_TO_IMPL(stream) ((libcurl_stream_impl_t *)(stream)) + +/********************************Function headers******************************/ +axutil_stream_type_t AXIS2_CALL libcurl_stream_get_type( + axutil_stream_t * stream, + const axutil_env_t * env); + +int AXIS2_CALL libcurl_stream_write( + axutil_stream_t * stream, + const axutil_env_t * env, + const void *buffer, + size_t count); + +int AXIS2_CALL libcurl_stream_read( + axutil_stream_t * stream, + const axutil_env_t * env, + void *buffer, + size_t count); + +int AXIS2_CALL libcurl_stream_skip( + axutil_stream_t * stream, + const axutil_env_t * env, + int count); + +int AXIS2_CALL libcurl_stream_get_char( + axutil_stream_t * stream, + const axutil_env_t * env); + +/************************* End of function headers ****************************/ + +/* + * Internal function. Not exposed to outside + */ +AXIS2_EXTERN axutil_stream_t *AXIS2_CALL +axutil_stream_create_libcurl( + const axutil_env_t * env, + axis2_char_t * buffer, + unsigned int size) +{ + libcurl_stream_impl_t *stream_impl = NULL; + + AXIS2_PARAM_CHECK(env->error, buffer, NULL); + + stream_impl = + (libcurl_stream_impl_t *) AXIS2_MALLOC(env->allocator, + sizeof(libcurl_stream_impl_t)); + + if (!stream_impl) + { + AXIS2_HANDLE_ERROR(env, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE); + return NULL; + } + + stream_impl->buffer = buffer; + stream_impl->size = size; + stream_impl->read_len = 0; + stream_impl->stream_type = AXIS2_STREAM_MANAGED; + + axutil_stream_set_read(&(stream_impl->stream), env, libcurl_stream_read); + axutil_stream_set_write(&(stream_impl->stream), env, libcurl_stream_write); + axutil_stream_set_skip(&(stream_impl->stream), env, libcurl_stream_skip); + + return &(stream_impl->stream); +} + +void AXIS2_CALL +libcurl_stream_free( + void * stream, + const axutil_env_t * env) +{ + libcurl_stream_impl_t *stream_impl = NULL; + + stream_impl = AXIS2_INTF_TO_IMPL(stream); + AXIS2_FREE(env->allocator, stream_impl); + + return; +} + +int AXIS2_CALL +libcurl_stream_read( + axutil_stream_t * stream, + const axutil_env_t * env, + void *buffer, + size_t count) +{ + libcurl_stream_impl_t *stream_impl = NULL; + int read = 0; + int unread = 0; + + stream_impl = AXIS2_INTF_TO_IMPL(stream); + if (stream_impl->size >= (int)count) + /* We are sure that the difference lies within the int range */ + { + if (buffer && (stream_impl->size > stream_impl->read_len)) + { + unread = (stream_impl->size - stream_impl->read_len); + if (unread > (int)count) + /* We are sure that the difference lies within the int range */ + { + memcpy(buffer, &stream_impl->buffer[stream_impl->read_len], + count); + read = (int)count; + /* We are sure that the difference lies within the int range */ + stream_impl->read_len += read; + } + else + { + memcpy(buffer, &stream_impl->buffer[stream_impl->read_len], + unread); + read = unread; + stream_impl->read_len += read; + } + } + else + read = 0; + } + else + { + if (buffer && (stream_impl->size > stream_impl->read_len)) + { + memcpy(buffer, &stream_impl->buffer[stream_impl->read_len], + stream_impl->size - stream_impl->read_len); + read = stream_impl->size - stream_impl->read_len; + stream_impl->read_len += read; + } + else + read = 0; + } + return read; +} + +int AXIS2_CALL +libcurl_stream_write( + axutil_stream_t * stream, + const axutil_env_t * env, + const void *buffer, + size_t count) +{ + return (int)count; + /* We are sure that the difference lies within the int range */ +} + +int AXIS2_CALL +libcurl_stream_skip( + axutil_stream_t * stream, + const axutil_env_t * env, + int count) +{ + return 0; +} + +int AXIS2_CALL +libcurl_stream_get_char( + axutil_stream_t * stream, + const axutil_env_t * env) +{ + return 0; +} + +#endif /* AXIS2_LIBCURL_ENABLED */ + diff --git a/src/core/transport/http/sender/libcurl/libcurl_stream.h b/src/core/transport/http/sender/libcurl/libcurl_stream.h new file mode 100644 index 0000000..8a24fcc --- /dev/null +++ b/src/core/transport/http/sender/libcurl/libcurl_stream.h @@ -0,0 +1,51 @@ +/* + * 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. + */ + +#ifndef LIBCURL_STREAM_H +#define LIBCURL_STREAM_H + +#include <axis2_const.h> +#include <axis2_defines.h> +#include <axutil_env.h> +#include <axutil_stream.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + + /** brief Constructor for creating apche2 stream + * @return axutil_stream (libcurl) + */ + AXIS2_EXTERN axutil_stream_t *AXIS2_CALL + axutil_stream_create_libcurl( + const axutil_env_t * env, + axis2_char_t * buffer, + unsigned int size); + + /** @} */ + + void AXIS2_CALL libcurl_stream_free( + void * stream, + const axutil_env_t * env); + + +#ifdef __cplusplus +} +#endif + +#endif /* LIBCURL_STREAM_H */ |