summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpradeep kumar B <b.pradeep@samsung.com>2016-01-27 15:39:26 +0530
committerpradeep kumar B <b.pradeep@samsung.com>2016-01-28 11:02:32 +0530
commit298bb240a781b164cb7d91dd32672c3cf55e58ec (patch)
tree83486b4445115300a313e6df56d20d04a07192b2
parent18b86e39274c2ef1f5ec493a3c54b439ba445d76 (diff)
downloadhttp-298bb240a781b164cb7d91dd32672c3cf55e58ec.tar.gz
http-298bb240a781b164cb7d91dd32672c3cf55e58ec.tar.bz2
http-298bb240a781b164cb7d91dd32672c3cf55e58ec.zip
[capi-http] Added basic http GET method implementation
1.support multi session multi transaction Change-Id: If247c783cc357f2d4957572979bbcc99d7a0db63 Signed-off-by: pradeep kumar B <b.pradeep@samsung.com>
-rw-r--r--include/http_private.h18
-rw-r--r--src/http_common.c148
-rw-r--r--src/http_request.c131
-rw-r--r--src/http_session.c307
-rw-r--r--src/http_transaction.c384
-rw-r--r--test/http_test.c151
6 files changed, 1135 insertions, 4 deletions
diff --git a/include/http_private.h b/include/http_private.h
index 0923c05..8bb26ee 100644
--- a/include/http_private.h
+++ b/include/http_private.h
@@ -77,12 +77,16 @@ extern "C" {
} \
} while (0)
+static const int _HTTP_DEFAULT_CONNECTION_TIMEOUT = 30;
+static const int _HTTP_DEFAULT_HEADER_SIZE = 1024;
+static const int _MAX_HTTP_TRANSACTIONS_PER_SESSION_NORMAL = 1;
+static const int _MAX_HTTP_TRANSACTIONS_PER_SESSION_PIPE = 5;
+
typedef struct {
struct curl_slist *header_list;
} __http_header_h;
typedef struct {
- gchar *proxy_addr;
gchar *host_uri;
gchar *method;
gchar *encoding;
@@ -131,13 +135,21 @@ typedef struct {
} __http_transaction_h;
typedef struct {
- GIOChannel* channel;
- GSource* source;
+ curl_socket_t sockfd;
+ CURL *easy_handle;
int action;
+ guint event;
+ GIOChannel *channel;
__http_session_h *session;
} __http_socket_info_h;
+
+void print_curl_multi_errorCode(CURLMcode code);
+gchar* _get_http_method(http_method_e method);
+http_method_e _get_method(gchar* method);
+gchar* _get_proxy();
+
#ifdef __cplusplus
}
#endif
diff --git a/src/http_common.c b/src/http_common.c
new file mode 100644
index 0000000..bb5613e
--- /dev/null
+++ b/src/http_common.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
+ *
+ * Licensed 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 "http.h"
+#include "http_private.h"
+
+#include "net_connection.h"
+
+http_method_e _get_method(gchar* method)
+{
+ if (g_strcmp0(method, "GET") == 0) {
+ return HTTP_METHOD_GET;
+ } else if (g_strcmp0(method, "OPTIONS") == 0) {
+ return HTTP_METHOD_OPTIONS;
+ } else if (g_strcmp0(method, "HEAD") == 0) {
+ return HTTP_METHOD_HEAD;
+ } else if (g_strcmp0(method, "DELETE") == 0) {
+ return HTTP_METHOD_DELETE;
+ } else if (g_strcmp0(method, "TRACE") == 0) {
+ return HTTP_METHOD_TRACE;
+ } else if (g_strcmp0(method, "POST") == 0) {
+ return HTTP_METHOD_POST;
+ } else if (g_strcmp0(method, "PUT") == 0) {
+ return HTTP_METHOD_PUT;
+ } else if (g_strcmp0(method, "CONNECT") == 0) {
+ return HTTP_METHOD_CONNECT;
+ }
+
+ return HTTP_METHOD_NONE;
+}
+
+gchar* _get_http_method(http_method_e method)
+{
+ gchar* http_method = NULL;
+
+ switch (method) {
+ case HTTP_METHOD_GET:
+ http_method = g_strdup("GET");
+ break;
+
+ case HTTP_METHOD_OPTIONS:
+ http_method = g_strdup("OPTIONS");
+ break;
+
+ case HTTP_METHOD_HEAD:
+ http_method = g_strdup("HEAD");
+ break;
+
+ case HTTP_METHOD_DELETE:
+ http_method = g_strdup("DELETE");
+ break;
+
+ case HTTP_METHOD_TRACE:
+ http_method = g_strdup("TRACE");
+ break;
+
+ case HTTP_METHOD_POST:
+ http_method = g_strdup("POST");
+ break;
+
+ case HTTP_METHOD_PUT:
+ http_method = g_strdup("PUT");
+ break;
+
+ case HTTP_METHOD_CONNECT:
+ http_method = g_strdup("CONNECT");
+ break;
+
+ case HTTP_METHOD_NONE:
+ default:
+ http_method = NULL;
+ break;
+ }
+
+ return http_method;
+}
+
+void print_curl_multi_errorCode(CURLMcode code)
+{
+ const char* message = NULL;
+ switch (code) {
+ case CURLM_CALL_MULTI_PERFORM:
+ message = "CURLM_CALL_MULTI_PERFORM";
+ break;
+ case CURLM_BAD_HANDLE:
+ message = "CURLM_BAD_HANDLE";
+ break;
+ case CURLM_BAD_EASY_HANDLE:
+ message = "CURLM_BAD_EASY_HANDLE";
+ break;
+ case CURLM_OUT_OF_MEMORY:
+ message = "CURLM_OUT_OF_MEMORY";
+ break;
+ case CURLM_INTERNAL_ERROR:
+ message = "CURLM_INTERNAL_ERROR";
+ break;
+ case CURLM_BAD_SOCKET:
+ message = "CURLM_BAD_SOCKET";
+ break;
+ case CURLM_UNKNOWN_OPTION:
+ message = "CURLM_UNKNOWN_OPTION";
+ break;
+ case CURLM_LAST:
+ message = "CURLM_LAST";
+ break;
+ default:
+ message = "CURLM_UNKNOWN_ERROR";
+ break;
+ }
+
+ DBG("CURLMcode(%d): %s", code, message);
+}
+
+gchar* _get_proxy()
+{
+ connection_h connection = NULL;
+ gchar *proxy_addr = NULL;
+
+ if (connection_create(&connection) < 0) {
+ DBG("Fail to create network handle\n");
+ return NULL;
+ }
+
+ if (connection_get_proxy(connection, CONNECTION_ADDRESS_FAMILY_IPV4, &proxy_addr) < 0) {
+ DBG("Fail to get proxy address\n");
+ goto CATCH;
+ }
+
+CATCH:
+ if (connection_destroy(connection) < 0) {
+ DBG("Fail to destroy network handle\n");
+ }
+
+ return proxy_addr;
+}
diff --git a/src/http_request.c b/src/http_request.c
index 283a819..eae1ce3 100644
--- a/src/http_request.c
+++ b/src/http_request.c
@@ -15,4 +15,133 @@
*/
#include "http.h"
-#include "http_private.h" \ No newline at end of file
+#include "http_private.h"
+
+API int http_request_set_method(http_transaction_h http_transaction, http_method_e method)
+{
+ _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_transaction) is NULL\n");
+
+ __http_transaction_h *transaction = (__http_transaction_h *)http_transaction;
+ __http_request_h *request = transaction->request;
+
+ if (request->method) {
+ free(request->method);
+ request->method = NULL;
+ }
+
+ request->method = _get_http_method(method);
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_request_get_method(http_transaction_h http_transaction, http_method_e *method)
+{
+ _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_transaction) is NULL\n");
+ _retvm_if(method == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(method) is NULL\n");
+
+ __http_transaction_h *transaction = (__http_transaction_h *)http_transaction;
+ __http_request_h *request = transaction->request;
+
+ *method = _get_method(request->method);
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_request_set_version(http_transaction_h http_transaction, http_version_e version)
+{
+ _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_transaction) is NULL\n");
+
+ __http_transaction_h *transaction = (__http_transaction_h *)http_transaction;
+ __http_request_h *request = transaction->request;
+
+ request->http_version = version;
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_request_get_version(http_transaction_h http_transaction, http_version_e *version)
+{
+ _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_transaction) is NULL\n");
+ _retvm_if(version == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(version) is NULL\n");
+
+ __http_transaction_h *transaction = (__http_transaction_h *)http_transaction;
+ __http_request_h *request = transaction->request;
+
+ *version = request->http_version;
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_request_set_uri(http_transaction_h http_transaction, const char *host_uri)
+{
+ _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_transaction) is NULL\n");
+ _retvm_if(host_uri == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(host_uri) is NULL\n");
+
+ __http_transaction_h *transaction = (__http_transaction_h *)http_transaction;
+ __http_request_h *request = transaction->request;
+
+ request->host_uri = g_strdup(host_uri);
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_request_get_uri(http_transaction_h http_transaction, char **host_uri)
+{
+ _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_transaction) is NULL\n");
+ _retvm_if(host_uri == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(host_uri) is NULL\n");
+
+ __http_transaction_h *transaction = (__http_transaction_h *)http_transaction;
+ __http_request_h *request = transaction->request;
+
+ *host_uri = g_strdup(request->host_uri);
+ if (*host_uri == NULL) {
+ ERR("strdup is failed\n");
+ return HTTP_ERROR_OUT_OF_MEMORY;
+ }
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_request_set_accept_encoding(http_transaction_h http_transaction, const char *encoding)
+{
+ _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_transaction) is NULL\n");
+ _retvm_if(encoding == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(encoding) is NULL\n");
+
+ __http_transaction_h *transaction = (__http_transaction_h *)http_transaction;
+ __http_request_h *request = transaction->request;
+
+ request->encoding = g_strdup(encoding);
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_request_get_accept_encoding(http_transaction_h http_transaction, char **encoding)
+{
+ _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_transaction) is NULL\n");
+ _retvm_if(encoding == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(encoding) is NULL\n");
+
+ __http_transaction_h *transaction = (__http_transaction_h *)http_transaction;
+ __http_request_h *request = transaction->request;
+
+ *encoding = g_strdup(request->encoding);
+ if (*encoding == NULL) {
+ ERR("strdup is failed\n");
+ return HTTP_ERROR_OUT_OF_MEMORY;
+ }
+
+ return HTTP_ERROR_NONE;
+}
diff --git a/src/http_session.c b/src/http_session.c
index c01bbb6..9e9bb11 100644
--- a/src/http_session.c
+++ b/src/http_session.c
@@ -17,3 +17,310 @@
#include "http.h"
#include "http_private.h"
+void _check_curl_multi_status(gpointer user_data)
+{
+ __http_transaction_h *transaction = NULL;
+ __http_session_h *session = (__http_session_h *)user_data;
+
+ CURLMsg* message = NULL;
+ int count = 0;
+ CURL* curl_easy = NULL;
+ char* url = NULL;
+ CURLcode curl_code = CURLE_OK;
+
+ message = curl_multi_info_read(session->multi_handle, &count);
+
+ while (message != NULL) {
+ if (message->msg == CURLMSG_DONE) {
+ curl_easy = message->easy_handle;
+ curl_code = message->data.result;
+ curl_easy_getinfo(curl_easy, CURLINFO_PRIVATE, &transaction);
+ curl_easy_getinfo(curl_easy, CURLINFO_EFFECTIVE_URL, &url);
+
+ DBG("Completed -%s: result(%d)\n", url, curl_code);
+
+ if (curl_code == CURLE_OK) {
+ transaction->completed_cb();
+ } else {
+
+ }
+
+ curl_multi_remove_handle(session->multi_handle, curl_easy);
+ g_main_loop_quit((GMainLoop*)transaction->thread_loop);
+ }
+ message = curl_multi_info_read(session->multi_handle, &count);
+ }
+}
+
+gboolean timer_expired_callback(gpointer user_data)
+{
+ __http_session_h* session = (__http_session_h *)user_data;
+
+ CURLMcode ret;
+
+ ret = curl_multi_socket_action(session->multi_handle, CURL_SOCKET_TIMEOUT, 0, &(session->still_running));
+ if (ret == CURLM_OK) {
+ //DBG("CURLM_OK - Called curl_multi_socket_action()\n");
+ } else {
+ print_curl_multi_errorCode(ret);
+ }
+
+ _check_curl_multi_status(session);
+
+ return FALSE;
+}
+
+gboolean _handle_event(int fd, int action, gpointer user_data)
+{
+ __http_session_h *session = (__http_session_h *)user_data;
+
+ int running_handles = -1;
+
+ CURLMcode ret = CURLM_OK;
+
+ ret = curl_multi_socket_action(session->multi_handle, fd, action, &running_handles);
+ if (ret == CURLM_OK) {
+ //DBG("CURLM_OK: Called curl_multi_socket_action(%d)\n", action);
+ }
+ else {
+ print_curl_multi_errorCode(ret);
+ }
+
+ _check_curl_multi_status(session);
+
+ if (running_handles > 0) {
+ return TRUE;
+ } else {
+ DBG("last transfer done, kill timeout\n");
+ if (session->timer_event) {
+ g_source_remove(session->timer_event);
+ session->timer_event = 0;
+ }
+ return FALSE;
+ }
+}
+
+gboolean __handle_socket_received_event_cb(GIOChannel *channel, GIOCondition condition, gpointer user_data)
+{
+ int fd, action, ret;
+
+ if (condition & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
+ return FALSE;
+
+ fd = g_io_channel_unix_get_fd(channel);
+
+ //CURL_CSELECT_IN : 1, CURL_CSELECT_OUT: 2
+ action = (condition & G_IO_IN ? CURL_CSELECT_IN : 0) | (condition & G_IO_OUT ? CURL_CSELECT_OUT : 0);
+
+ ret = _handle_event(fd, action, user_data);
+ if (ret) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Clean up the __http_socket_info_h structure */
+static void _remove_socket_info(__http_socket_info_h *sock_info)
+{
+ if (!sock_info) {
+ return;
+ }
+ if (sock_info->event) {
+ g_source_remove(sock_info->event);
+ sock_info->event = 0;
+ }
+ if (sock_info->channel) {
+ g_io_channel_unref(sock_info->channel);
+ sock_info->channel = NULL;
+ }
+ g_free(sock_info);
+ sock_info = NULL;
+}
+
+/* Assign socket information to a __http_socket_info_h structure */
+static void _set_socket_info(__http_socket_info_h *sock_info, curl_socket_t fd, CURL *curl_easy, int action, void *user_data)
+{
+ __http_session_h *session = (__http_session_h *)user_data;
+ GIOCondition condition = (action & CURL_POLL_IN ? G_IO_IN : 0) | (action & CURL_POLL_OUT ? G_IO_OUT: 0);
+
+ sock_info->sockfd = fd;
+ sock_info->action = action;
+ sock_info->easy_handle = curl_easy;
+ if (sock_info->event) {
+ g_source_remove(sock_info->event);
+ sock_info->event = 0;
+ }
+ sock_info->event = g_io_add_watch(sock_info->channel, condition, __handle_socket_received_event_cb, session);
+}
+
+/* Initialize a new Socket Info structure */
+static void _add_socket_info(curl_socket_t fd, CURL *curl_easy, int action, void *user_data)
+{
+ __http_session_h *session = (__http_session_h *)user_data;
+ __http_socket_info_h *sock_info = (__http_socket_info_h *)malloc(sizeof(__http_socket_info_h));
+
+ sock_info->session = session;
+ sock_info->channel = g_io_channel_unix_new(fd);
+ sock_info->event = 0;
+ _set_socket_info(sock_info, fd, curl_easy, action, session);
+ curl_multi_assign(session->multi_handle, fd, sock_info);
+}
+
+int __handle_socket_cb(CURL *curl_easy, curl_socket_t fd, int action, void *user_data, void *socketp)
+{
+ __http_session_h *session = (__http_session_h *)user_data;
+ __http_socket_info_h *sock_info = (__http_socket_info_h*) socketp;
+
+ static const char *actionstr[]={ "none", "IN", "OUT", "INOUT", "REMOVE"};
+
+ DBG("__handle_socket_cb: fd=%d easy_handle=%p action=%s ", fd, curl_easy, actionstr[action]);
+ if (action == CURL_POLL_REMOVE) {
+ DBG("CURL_POLL_REMOVE\n");
+ _remove_socket_info(sock_info);
+ } else {
+ if (!sock_info) {
+ DBG("Adding data: %s%s\n", action & CURL_POLL_IN ? "READ":"", action & CURL_POLL_OUT ? "WRITE":"" );
+ _add_socket_info(fd, curl_easy, action, session);
+ }
+ else {
+ DBG("Changing action from %d to %d\n", sock_info->action, action);
+ _set_socket_info(sock_info, fd, curl_easy, action, session);
+ }
+ }
+
+ return 0;
+}
+
+int __handle_timer_cb(CURLM *curl_multi, long timeout_ms, void *user_data)
+{
+ __http_session_h* session = (__http_session_h *)user_data;
+
+ session->timer_event = g_timeout_add(timeout_ms , timer_expired_callback , session);
+
+ return 0;
+}
+
+API int http_init()
+{
+ if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
+ DBG("curl_global_init failed, so returning!\n");
+ return HTTP_ERROR_OPERATION_FAILED;
+ }
+
+ return HTTP_ERROR_NONE;
+}
+
+API void http_deinit()
+{
+ curl_global_cleanup();
+}
+
+API int http_create_session(http_session_h *http_session, http_session_mode_e mode)
+{
+ _retvm_if(http_session == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_session) is NULL\n");
+
+ __http_session_h *session = NULL;
+
+ session = (__http_session_h *)malloc(sizeof(__http_session_h));
+
+ session->multi_handle = curl_multi_init();
+ session->active_transaction_count = 0;
+ session->session_mode = mode;
+ session->auto_redirect = FALSE;
+
+ curl_multi_setopt(session->multi_handle, CURLMOPT_SOCKETFUNCTION, __handle_socket_cb);
+ curl_multi_setopt(session->multi_handle, CURLMOPT_SOCKETDATA, session);
+ curl_multi_setopt(session->multi_handle, CURLMOPT_TIMERFUNCTION, __handle_timer_cb);
+ curl_multi_setopt(session->multi_handle, CURLMOPT_TIMERDATA, session);
+
+ if (mode == HTTP_SESSION_MODE_PIPELINING) {
+ curl_multi_setopt(session->multi_handle, CURLMOPT_PIPELINING, 1L);
+ }
+
+ *http_session = (http_session_h)session;
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_delete_session(http_session_h http_session)
+{
+ _retvm_if(http_session == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_session) is NULL\n");
+
+ __http_session_h *session = (__http_session_h *)http_session;
+
+ if (session->multi_handle) {
+ curl_multi_cleanup(session->multi_handle);
+ session->multi_handle = NULL;
+ }
+
+ session->active_transaction_count = 0;
+ session->still_running = 0;
+ session->auto_redirect = FALSE;
+
+ free(session);
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_session_set_auto_redirection(http_session_h http_session, bool enable)
+{
+ _retvm_if(http_session == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_session) is NULL\n");
+
+ __http_session_h *session = (__http_session_h *)http_session;
+
+ session->auto_redirect = enable;
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_session_get_auto_redirection(http_session_h http_session, bool *auto_redirect)
+{
+ _retvm_if(http_session == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_session) is NULL\n");
+ _retvm_if(auto_redirect == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(auto_redirect) is NULL\n");
+
+ __http_session_h *session = (__http_session_h *)http_session;
+
+ *auto_redirect = session->auto_redirect;
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_session_get_active_transaction_count(http_session_h http_session, int *active_transaction_count)
+{
+ _retvm_if(http_session == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_session) is NULL\n");
+ _retvm_if(active_transaction_count == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(active_transaction_count) is NULL\n");
+
+ __http_session_h *session = (__http_session_h *)http_session;
+
+ *active_transaction_count = session->active_transaction_count;
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_session_get_max_transaction_count(http_session_h http_session, int *transaction_count)
+{
+ _retvm_if(http_session == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_session) is NULL\n");
+ _retvm_if(transaction_count == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(transaction_count) is NULL\n");
+
+ __http_session_h *session = (__http_session_h *)http_session;
+
+ if (session->session_mode == HTTP_SESSION_MODE_NORMAL) {
+ *transaction_count = _MAX_HTTP_TRANSACTIONS_PER_SESSION_NORMAL;
+ } else if (session->session_mode == HTTP_SESSION_MODE_PIPELINING) {
+ *transaction_count = _MAX_HTTP_TRANSACTIONS_PER_SESSION_PIPE;
+ } else {
+ *transaction_count = -1;
+ }
+
+ return HTTP_ERROR_NONE;
+}
diff --git a/src/http_transaction.c b/src/http_transaction.c
index c01bbb6..c33d535 100644
--- a/src/http_transaction.c
+++ b/src/http_transaction.c
@@ -17,3 +17,387 @@
#include "http.h"
#include "http_private.h"
+curl_socket_t __handle_opensocket_cb(void *client_fd, curlsocktype purpose, struct curl_sockaddr *address)
+{
+ int fd = socket(address->family, address->socktype, address->protocol);
+ DBG("socket opened:%d\n", fd);
+
+ return fd;
+}
+
+size_t __handle_header_cb(char *buffer, size_t size, size_t nmemb, gpointer user_data)
+{
+ __http_transaction_h *transaction = (__http_transaction_h *)user_data;
+ size_t written = size * nmemb;
+
+ transaction->header_cb(buffer, written);
+
+ return written;
+}
+
+size_t __handle_body_cb(char *ptr, size_t size, size_t nmemb, gpointer user_data)
+{
+ __http_transaction_h *transaction = (__http_transaction_h *)user_data;
+ size_t written = size * nmemb;
+
+ transaction->body_cb(ptr, size, nmemb);
+
+ return written;
+}
+
+size_t __http_debug_received(CURL* easy_handle, curl_infotype type, char* byte, size_t size, void *user_data)
+{
+ char log_buffer[_HTTP_DEFAULT_HEADER_SIZE];
+ int log_size = 0;
+
+ if (_HTTP_DEFAULT_HEADER_SIZE > size) {
+ log_size = size;
+ }
+ else {
+ log_size = _HTTP_DEFAULT_HEADER_SIZE - 1;
+ }
+
+ if (type == CURLINFO_TEXT) {
+ strncpy(log_buffer, byte, log_size);
+ log_buffer[log_size] = '\0';
+ DBG("[DEBUG] %s", log_buffer);
+ }
+ else if (type == CURLINFO_HEADER_IN || type == CURLINFO_HEADER_OUT) {
+ //Ignore the body message.
+ if (size >= 2 && byte[0] == 0x0D && byte[1] == 0x0A) {
+ return 0;
+ }
+ else {
+ strncpy(log_buffer, byte, log_size);
+ log_buffer[log_size] = '\0';
+ DBG("[DEBUG] %s", log_buffer);
+ }
+ }
+
+ return 0;
+}
+
+int _transaction_submit(gpointer user_data)
+{
+ __http_transaction_h *transaction = (__http_transaction_h *)user_data;
+ __http_session_h *session = transaction->session;
+ __http_request_h *request = transaction->request;
+
+ CURLMcode ret = CURLM_OK;
+ gchar *proxy_addr = NULL;
+
+ transaction->easy_handle = curl_easy_init();
+
+ if (request->http_version == HTTP_VERSION_1_0) {
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ } else {
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ }
+
+ if (request->host_uri)
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_URL, request->host_uri);
+
+ proxy_addr = _get_proxy();
+ if (proxy_addr) {
+ DBG("Proxy address:%s\n", proxy_addr);
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_PROXY, proxy_addr);
+ free(proxy_addr);
+ }
+
+ if (request->method)
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_CUSTOMREQUEST, request->method);
+
+ if (transaction->interface_name)
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_INTERFACE, transaction->interface_name);
+
+ if (request->encoding)
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_ENCODING, request->encoding);
+
+ //The connection timeout is 30s. (default)
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_CONNECTTIMEOUT, _HTTP_DEFAULT_CONNECTION_TIMEOUT);
+
+ if (transaction->timeout > 0) {
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_TIMEOUT, transaction->timeout);
+ } else if (transaction->timeout == 0) {
+ //Set the transaction timeout. The timeout includes connection timeout.
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_LOW_SPEED_LIMIT, 1L);
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_LOW_SPEED_TIME, 30L);
+ }
+
+ if (session->auto_redirect) {
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_FOLLOWLOCATION, 1L);
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
+ DBG("Enabled Auto-Redirection\n");
+ } else {
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_FOLLOWLOCATION, 0L);
+ DBG("Disabled Auto-Redirection\n");
+ }
+
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_HEADERFUNCTION, __handle_header_cb);
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_HEADERDATA, transaction);
+
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_WRITEFUNCTION, __handle_body_cb);
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_WRITEDATA, transaction);
+
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_VERBOSE, 1L);
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_DEBUGFUNCTION, __http_debug_received);
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_ERRORBUFFER, transaction->error);
+
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_OPENSOCKETDATA, &transaction->socket_fd);
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_OPENSOCKETFUNCTION, __handle_opensocket_cb);
+
+ curl_easy_setopt(transaction->easy_handle, CURLOPT_PRIVATE, transaction);
+
+ ret = curl_multi_add_handle(session->multi_handle, transaction->easy_handle);
+ if (ret == CURLM_OK) {
+ DBG("CURLM_OK: Called curl_multi_add_handle().");
+ } else {
+ print_curl_multi_errorCode(ret);
+ ERR("Failed to add easy_handle to curl_multi_add_handle()");
+ }
+
+ return HTTP_ERROR_NONE;
+}
+
+void* thread_callback(void *user_data)
+{
+ __http_transaction_h *transaction = (__http_transaction_h *)user_data;
+
+ transaction->thread_loop = g_main_loop_new(NULL, FALSE);
+
+ _transaction_submit(transaction);
+
+ g_main_loop_run(transaction->thread_loop);
+
+ g_main_loop_unref(transaction->thread_loop);
+ transaction->thread_loop = NULL;
+ DBG("thread exited.\n");
+
+ return NULL;
+}
+
+API int http_open_transaction(http_session_h http_session, http_method_e method, http_transaction_header_cb transaction_header_callback,
+ http_transaction_body_cb transaction_body_callback, http_transaction_write_cb transaction_write_callback,
+ http_transaction_completed_cb transaction_completed_cb, http_transaction_aborted_cb transaction_aborted_cb, http_transaction_h *http_transaction)
+{
+ _retvm_if(http_session == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_session) is NULL\n");
+ _retvm_if(transaction_header_callback == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(transaction_header_callback) is NULL\n");
+ _retvm_if(transaction_body_callback == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(transaction_body_callback) is NULL\n");
+ _retvm_if(transaction_write_callback == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(transaction_write_callback) is NULL\n");
+ _retvm_if(transaction_completed_cb == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(transaction_completed_cb) is NULL\n");
+ _retvm_if(transaction_aborted_cb == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(transaction_aborted_cb) is NULL\n");
+
+ __http_transaction_h *transaction = NULL;
+
+ transaction = (__http_transaction_h *)malloc(sizeof(__http_transaction_h));
+
+ transaction->easy_handle = NULL;
+ transaction->interface_name = NULL;
+ transaction->timeout = 0;
+ transaction->error[0] = '\0';
+
+ transaction->header_cb = transaction_header_callback;
+ transaction->body_cb = transaction_body_callback;
+ transaction->write_cb = transaction_write_callback;
+ transaction->completed_cb = transaction_completed_cb;
+ transaction->aborted_cb = transaction_aborted_cb;
+
+ transaction->upload_progress_cb = NULL;
+ transaction->download_progress_cb = NULL;
+
+ transaction->session = http_session;
+ transaction->session->active_transaction_count++;
+
+ transaction->request = (__http_request_h *)malloc(sizeof(__http_request_h));
+ transaction->response = (__http_response_h *)malloc(sizeof(__http_response_h));
+ transaction->header = (__http_header_h *)malloc(sizeof(__http_header_h));
+
+ transaction->request->host_uri = NULL;
+
+ transaction->request->method = _get_http_method(method);
+
+ transaction->request->encoding = NULL;
+ transaction->request->body = NULL;
+ transaction->request->http_version = HTTP_VERSION_1_1;
+
+ transaction->thread = NULL;
+
+ *http_transaction = (http_transaction_h)transaction;
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_transaction_submit(http_transaction_h http_transaction)
+{
+ _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_transaction) is NULL\n");
+
+ __http_transaction_h *transaction = (__http_transaction_h *)http_transaction;
+
+ transaction->thread = g_thread_new("transaction_thread", thread_callback, transaction);
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_transaction_close(http_transaction_h http_transaction)
+{
+ _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_transaction) is NULL\n");
+
+ __http_transaction_h *transaction = NULL;
+ __http_session_h *session = NULL;
+ __http_header_h *header = NULL;
+ __http_request_h *request = NULL;
+ __http_response_h *response = NULL;
+
+ transaction = (__http_transaction_h *)http_transaction;
+ session = transaction->session;
+ request = transaction->request;
+ response = transaction->response;
+ header = transaction->header;
+
+ if (session) {
+ session->active_transaction_count--;
+ }
+
+ if (transaction) {
+
+ g_thread_join(transaction->thread);
+ transaction->thread = NULL;
+
+ if (transaction->easy_handle != NULL) {
+ curl_easy_cleanup(transaction->easy_handle);
+ transaction->easy_handle = NULL;
+ }
+
+ if (transaction->interface_name != NULL) {
+ free(transaction->interface_name);
+ transaction->interface_name = NULL;
+ }
+
+ transaction->timeout = 0;
+ transaction->error[0] = '\0';
+
+ transaction->header_cb = NULL;
+ transaction->body_cb = NULL;
+ transaction->write_cb = NULL;
+ transaction->completed_cb = NULL;
+ transaction->aborted_cb = NULL;
+
+ transaction->upload_progress_cb = NULL;
+ transaction->download_progress_cb = NULL;
+
+ if (request) {
+ if (request->host_uri != NULL) {
+ free(request->host_uri);
+ request->host_uri = NULL;
+ }
+
+ if (request->method != NULL) {
+ free(request->method);
+ request->method = NULL;
+ }
+
+ if (request->encoding != NULL) {
+ free(request->encoding);
+ request->encoding = NULL;
+ }
+
+ if (request->body != NULL) {
+ free(request->body);
+ request->body = NULL;
+ }
+
+ free(request);
+ }
+ free(response);
+ free(header);
+
+ free(transaction);
+ transaction = NULL;
+ }
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_transaction_set_progress_callbacks(http_transaction_h http_transaction, http_transaction_upload_progress_cb upload_progress_cb,
+ http_transaction_download_progress_cb download_progress_cb)
+{
+ _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_transaction) is NULL\n");
+ _retvm_if(upload_progress_cb == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(upload_progress_cb) is NULL\n");
+ _retvm_if(download_progress_cb == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(download_progress_cb) is NULL\n");
+
+ __http_transaction_h *transaction = (__http_transaction_h *)http_transaction;
+
+ transaction->upload_progress_cb = upload_progress_cb;
+ transaction->download_progress_cb = download_progress_cb;
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_transaction_set_timeout(http_transaction_h http_transaction, int timeout)
+{
+ _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_transaction) is NULL\n");
+
+ __http_transaction_h *transaction = (__http_transaction_h *)http_transaction;
+
+ transaction->timeout = timeout;
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_transaction_get_timeout(http_transaction_h http_transaction, int *timeout)
+{
+ _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_transaction) is NULL\n");
+ _retvm_if(timeout == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(timeout) is NULL\n");
+
+ __http_transaction_h *transaction = (__http_transaction_h *)http_transaction;
+
+ *timeout = transaction->timeout;
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_transaction_set_interface_name(http_transaction_h http_transaction, const char *interface_name)
+{
+ _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_transaction) is NULL\n");
+ _retvm_if(interface_name == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(interface_name) is NULL\n");
+
+ __http_transaction_h *transaction = (__http_transaction_h *)http_transaction;
+
+ transaction->interface_name = g_strdup(interface_name);
+
+ return HTTP_ERROR_NONE;
+}
+
+API int http_transaction_get_interface_name(http_transaction_h http_transaction, char **interface_name)
+{
+ _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(http_transaction) is NULL\n");
+ _retvm_if(interface_name == NULL, HTTP_ERROR_INVALID_PARAMETER,
+ "parameter(interface_name) is NULL\n");
+
+ __http_transaction_h *transaction = (__http_transaction_h *)http_transaction;
+
+ *interface_name = g_strdup(transaction->interface_name);
+ if (*interface_name == NULL) {
+ ERR("strdup is failed\n");
+ return HTTP_ERROR_OUT_OF_MEMORY;
+ }
+
+ return HTTP_ERROR_NONE;
+}
diff --git a/test/http_test.c b/test/http_test.c
index 3207656..87a2b4d 100644
--- a/test/http_test.c
+++ b/test/http_test.c
@@ -21,9 +21,160 @@
#include "http.h"
+static GMainLoop *mainloop = NULL;
+
+#define DBG printf
+
+FILE* fp1 = NULL;
+FILE* fp2 = NULL;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////Request 1 Callbacks////////////////////////////////////////////////////////////////////////////
+void transaction_header_cb(char *header, size_t header_len)
+{
+ DBG("########################## 1:transaction_header_cb#########################################\n");
+
+ if (!fp1)
+ fp1 = fopen ("./google.html", "w+");
+
+}
+
+void transaction_body_cb(char *body, size_t size, size_t nmemb)
+{
+ DBG("########################## 1:transaction_body_cb#########################################\n");
+ //DBG("Body:%s\n", body);
+ int written = size * nmemb;
+
+ if (written) {
+ fwrite(body, size, nmemb, fp1);
+ }
+}
+
+void transaction_write_cb(int recommended_chunk_size)
+{
+ DBG("########################## 1:transaction_write_cb#########################################\n");
+
+ DBG("recommended_chunk_size:%d\n", recommended_chunk_size);
+}
+
+void transaction_completed_cb(void)
+{
+ DBG("########################## 1:transaction_completed_cb#########################################\n");
+
+ fclose(fp1);
+
+ //g_main_loop_quit((GMainLoop*)mainloop);
+}
+
+void transaction_aborted_cb(int reason)
+{
+ DBG("########################## 1:transaction_aborted_cb#########################################\n");
+
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////Request 2 Callbacks////////////////////////////////////////////////////////////////////////////
+void transaction_header_callback(char *header, size_t header_len)
+{
+ DBG("########################## 2: transaction_header_callback#########################################\n");
+
+ if (!fp2)
+ fp2 = fopen ("./ibnlive.html", "w+");
+
+}
+
+void transaction_body_callback(char *body, size_t size, size_t nmemb)
+{
+ DBG("########################## 2: transaction_body_callback#########################################\n");
+ //DBG("Body:%s\n", body);
+ int written = size * nmemb;
+
+ if (written) {
+ fwrite(body, size, nmemb, fp2);
+ }
+}
+
+void transaction_write_callback(int recommended_chunk_size)
+{
+ DBG("########################## 2:transaction_write_callback#########################################\n");
+
+ DBG("recommended_chunk_size:%d\n", recommended_chunk_size);
+}
+
+void transaction_completed_callback(void)
+{
+ DBG("########################## 2:transaction_completed_callback #########################################\n");
+
+ fclose(fp2);
+
+ g_main_loop_quit((GMainLoop*)mainloop);
+}
+
+void transaction_aborted_callback(int reason)
+{
+ DBG("########################## 2:transaction_aborted_callback#########################################\n");
+
+}
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+http_transaction_h create_http_request(http_session_h session_handle, gchar* host_url, http_transaction_header_cb header_cb, http_transaction_body_cb body_cb, http_transaction_write_cb write_cb,
+ http_transaction_completed_cb completed_cb, http_transaction_aborted_cb aborted_cb)
+{
+ http_transaction_h transaction_handle = NULL;
+
+ http_session_set_auto_redirection(session_handle, TRUE);
+
+ http_open_transaction(session_handle, HTTP_METHOD_GET, (http_transaction_header_cb)header_cb,
+ (http_transaction_body_cb)body_cb, (http_transaction_write_cb)write_cb, (http_transaction_completed_cb)completed_cb,
+ (http_transaction_aborted_cb)aborted_cb, &transaction_handle);
+
+ http_request_set_uri(transaction_handle, host_url);
+
+ return transaction_handle;
+}
+
+int submit_http_request(http_transaction_h transaction_handle)
+{
+ http_transaction_submit(transaction_handle);
+
+ return 0;
+}
int main()
{
+ http_session_h session_handle = NULL;
+ http_transaction_h transaction_handle1 = NULL;
+ http_transaction_h transaction_handle2 = NULL;
+
+
+ DBG("########################## main:Enter#########################################\n");
+
+ mainloop = g_main_loop_new(NULL, FALSE);
+
+ http_init();
+
+ http_create_session(&session_handle, HTTP_SESSION_MODE_NORMAL);
+
+ transaction_handle1 = create_http_request(session_handle, "http://www.google.com", transaction_header_cb, transaction_body_cb,
+ transaction_write_cb, transaction_completed_cb, transaction_aborted_cb);
+ transaction_handle2 = create_http_request(session_handle, "http://www.ibnlive.com", transaction_header_callback, transaction_body_callback,
+ transaction_write_callback, transaction_completed_callback, transaction_aborted_callback);
+
+ submit_http_request(transaction_handle1);
+ submit_http_request(transaction_handle2);
+
+ g_main_loop_run(mainloop);
+
+ http_transaction_close(transaction_handle1);
+ transaction_handle1 = NULL;
+ http_transaction_close(transaction_handle2);
+ transaction_handle1 = NULL;
+ http_delete_session(session_handle);
+ session_handle = NULL;
+ http_deinit();
+
+ g_main_loop_unref(mainloop);
+ DBG("########################## main:Exit#########################################\n");
return 0;
}