diff options
author | pradeep kumar B <b.pradeep@samsung.com> | 2016-01-27 15:39:26 +0530 |
---|---|---|
committer | pradeep kumar B <b.pradeep@samsung.com> | 2016-01-28 11:02:32 +0530 |
commit | 298bb240a781b164cb7d91dd32672c3cf55e58ec (patch) | |
tree | 83486b4445115300a313e6df56d20d04a07192b2 | |
parent | 18b86e39274c2ef1f5ec493a3c54b439ba445d76 (diff) | |
download | http-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.h | 18 | ||||
-rw-r--r-- | src/http_common.c | 148 | ||||
-rw-r--r-- | src/http_request.c | 131 | ||||
-rw-r--r-- | src/http_session.c | 307 | ||||
-rw-r--r-- | src/http_transaction.c | 384 | ||||
-rw-r--r-- | test/http_test.c | 151 |
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; } |