[capi-http] Added basic http GET method implementation 85/58085/4
authorpradeep kumar B <b.pradeep@samsung.com>
Wed, 27 Jan 2016 10:09:26 +0000 (15:39 +0530)
committerpradeep kumar B <b.pradeep@samsung.com>
Thu, 28 Jan 2016 05:32:32 +0000 (11:02 +0530)
1.support multi session multi transaction

Change-Id: If247c783cc357f2d4957572979bbcc99d7a0db63
Signed-off-by: pradeep kumar B <b.pradeep@samsung.com>
include/http_private.h
src/http_common.c [new file with mode: 0644]
src/http_request.c
src/http_session.c
src/http_transaction.c
test/http_test.c

index 0923c05..8bb26ee 100644 (file)
@@ -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 (file)
index 0000000..bb5613e
--- /dev/null
@@ -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;
+}
index 283a819..eae1ce3 100644 (file)
  */
 
 #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;
+}
index c01bbb6..9e9bb11 100644 (file)
 #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;
+}
index c01bbb6..c33d535 100644 (file)
 #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;
+}
index 3207656..87a2b4d 100644 (file)
 
 #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;
 }