summaryrefslogtreecommitdiff
path: root/agent
diff options
context:
space:
mode:
Diffstat (limited to 'agent')
-rwxr-xr-xagent/CMakeLists.txt85
-rwxr-xr-xagent/download-agent-basic.c431
-rwxr-xr-xagent/download-agent-client-mgr.c631
-rwxr-xr-xagent/download-agent-debug.c205
-rwxr-xr-xagent/download-agent-dl-info-util.c498
-rwxr-xr-xagent/download-agent-dl-mgr.c314
-rwxr-xr-xagent/download-agent-encoding.c282
-rwxr-xr-xagent/download-agent-file.c1138
-rwxr-xr-xagent/download-agent-http-mgr.c1744
-rwxr-xr-xagent/download-agent-http-misc.c64
-rwxr-xr-xagent/download-agent-http-msg-handler.c1333
-rwxr-xr-xagent/download-agent-http-queue.c390
-rwxr-xr-xagent/download-agent-interface.c234
-rwxr-xr-xagent/download-agent-mime-util.c401
-rwxr-xr-xagent/download-agent-plugin-conf.c122
-rwxr-xr-xagent/download-agent-plugin-libsoup.c1002
-rwxr-xr-xagent/download-agent-utils-dl-id-history.c71
-rwxr-xr-xagent/download-agent-utils.c248
-rwxr-xr-xagent/include/download-agent-basic.h29
-rwxr-xr-xagent/include/download-agent-client-mgr.h90
-rwxr-xr-xagent/include/download-agent-debug.h107
-rwxr-xr-xagent/include/download-agent-defs.h89
-rwxr-xr-xagent/include/download-agent-dl-info-util.h257
-rwxr-xr-xagent/include/download-agent-dl-mgr.h33
-rwxr-xr-xagent/include/download-agent-encoding.h27
-rwxr-xr-xagent/include/download-agent-file.h47
-rwxr-xr-xagent/include/download-agent-http-mgr.h47
-rwxr-xr-xagent/include/download-agent-http-misc.h47
-rwxr-xr-xagent/include/download-agent-http-msg-handler.h120
-rwxr-xr-xagent/include/download-agent-http-queue.h126
-rwxr-xr-xagent/include/download-agent-interface.h478
-rwxr-xr-xagent/include/download-agent-mime-util.h40
-rwxr-xr-xagent/include/download-agent-plugin-conf.h27
-rwxr-xr-xagent/include/download-agent-plugin-http-interface.h51
-rwxr-xr-xagent/include/download-agent-plugin-libsoup.h75
-rwxr-xr-xagent/include/download-agent-pthread.h147
-rwxr-xr-xagent/include/download-agent-type.h35
-rwxr-xr-xagent/include/download-agent-utils-dl-id-history.h35
-rwxr-xr-xagent/include/download-agent-utils.h54
39 files changed, 11154 insertions, 0 deletions
diff --git a/agent/CMakeLists.txt b/agent/CMakeLists.txt
new file mode 100755
index 0000000..92c1677
--- /dev/null
+++ b/agent/CMakeLists.txt
@@ -0,0 +1,85 @@
+PROJECT(downloadagent2 C)
+
+IF("${CMAKE_BUILD_TYPE}" STREQUAL "")
+ SET(CMAKE_BUILD_TYPE "Debug")
+ENDIF("${CMAKE_BUILD_TYPE}" STREQUAL "")
+MESSAGE("Build type: ${CMAKE_BUILD_TYPE}")
+
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(VERSION "0.0.1")
+FIND_PROGRAM(UNAME NAMES uname)
+EXEC_PROGRAM("${UNAME}" ARGS "-m" OUTPUT_VARIABLE "ARCH")
+
+#DA Engine Include Directory
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/include)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(subpkgs REQUIRED
+ libsoup-2.4
+ xdgmime
+ vconf
+ capi-network-connection
+ glib-2.0
+ dlog
+ libtzplatform-config
+)
+
+FOREACH(flag ${subpkgs_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -Wall")
+
+IF("${ARCH}" MATCHES "^arm.*")
+ ADD_DEFINITIONS("-D_TARGET")
+ SET(CMAKE_C_FLAGS_RELEASE "-mabi=aapcs-linux -msoft-float -O2")
+ENDIF("${ARCH}" MATCHES "^arm.*")
+
+ADD_DEFINITIONS("-D_EFL_PLATFORM")
+#allow to install widget, deb pkg and apk for testing
+ADD_DEFINITIONS("-DDA_DEBUG_USING_DLOG")
+#This should be removed when release a target
+ADD_DEFINITIONS("-D_SAMSUNG_MIME_POLICY")
+
+#############################################################################
+#+++++++++++++++++++++++++DA ENGINE+++++++++++++++++++++++++++++++++++++++++++
+#############################################################################
+
+SET(SRCS_PATH ".")
+SET(SRCS_DA_ENGINE
+ ${SRCS_PATH}/download-agent-debug.c
+ ${SRCS_PATH}/download-agent-interface.c
+ ${SRCS_PATH}/download-agent-client-mgr.c
+ ${SRCS_PATH}/download-agent-dl-mgr.c
+ ${SRCS_PATH}/download-agent-dl-info-util.c
+ ${SRCS_PATH}/download-agent-http-queue.c
+ ${SRCS_PATH}/download-agent-http-misc.c
+ ${SRCS_PATH}/download-agent-http-mgr.c
+ ${SRCS_PATH}/download-agent-http-msg-handler.c
+ ${SRCS_PATH}/download-agent-encoding.c
+ ${SRCS_PATH}/download-agent-utils.c
+ ${SRCS_PATH}/download-agent-utils-dl-id-history.c
+ ${SRCS_PATH}/download-agent-basic.c
+ ${SRCS_PATH}/download-agent-file.c
+ ${SRCS_PATH}/download-agent-plugin-libsoup.c
+ ${SRCS_PATH}/download-agent-plugin-conf.c
+ ${SRCS_PATH}/download-agent-mime-util.c
+)
+
+SET(HEADERS
+ include/download-agent-defs.h
+ include/download-agent-interface.h
+)
+
+ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS_DA_ENGINE})
+#TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${subpkgs_LDFLAGS} "-ldl")
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${subpkgs_LDFLAGS})
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION 0.0.1)
+
+#############################################################################
+#+++++++++++++++++++++++++INSTALLATION++++++++++++++++++++++++++++++++++++++++
+#############################################################################
+
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR} COMPONENT RuntimeLibraries)
+
diff --git a/agent/download-agent-basic.c b/agent/download-agent-basic.c
new file mode 100755
index 0000000..73fc892
--- /dev/null
+++ b/agent/download-agent-basic.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <stdlib.h>
+
+#include "download-agent-basic.h"
+#include "download-agent-debug.h"
+#include "download-agent-client-mgr.h"
+#include "download-agent-utils.h"
+#include "download-agent-http-mgr.h"
+#include "download-agent-http-misc.h"
+#include "download-agent-dl-mgr.h"
+#include "download-agent-pthread.h"
+#include "download-agent-file.h"
+
+static void* __thread_start_download(void* data);
+void __thread_clean_up_handler_for_start_download(void *arg);
+
+static da_result_t __make_source_info_basic_download(
+ stage_info *stage,
+ client_input_t *client_input);
+static da_result_t __download_content(stage_info *stage);
+
+da_result_t start_download(const char *url , int *dl_id)
+{
+ DA_LOG_FUNC_LOGD(Default);
+ return start_download_with_extension(url, dl_id, NULL);
+}
+
+da_result_t start_download_with_extension(
+ const char *url,
+ int *dl_id,
+ extension_data_t *extension_data)
+{
+ da_result_t ret = DA_RESULT_OK;
+ int slot_id = 0;
+ const char **request_header = DA_NULL;
+ const char *install_path = DA_NULL;
+ const char *file_name = DA_NULL;
+ const char *etag = DA_NULL;
+ const char *temp_file_path = DA_NULL;
+ const char *pkg_name = DA_NULL;
+ int request_header_count = 0;
+ void *user_data = DA_NULL;
+ client_input_t *client_input = DA_NULL;
+ client_input_basic_t *client_input_basic = DA_NULL;
+ download_thread_input *thread_info = DA_NULL;
+ pthread_attr_t thread_attr;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ if (extension_data) {
+ request_header = extension_data->request_header;
+ if (extension_data->request_header_count)
+ request_header_count = extension_data->request_header_count;
+ install_path = extension_data->install_path;
+ file_name = extension_data->file_name;
+ user_data = extension_data->user_data;
+ etag = extension_data->etag;
+ temp_file_path = extension_data->temp_file_path;
+ pkg_name = extension_data->pkg_name;
+ }
+
+ ret = get_available_slot_id(&slot_id);
+ if (DA_RESULT_OK != ret)
+ return ret;
+
+ *dl_id = GET_DL_ID(slot_id);
+
+ client_input = (client_input_t *)calloc(1, sizeof(client_input_t));
+ if (!client_input) {
+ DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ } else {
+ client_input->user_data = user_data;
+ if (install_path) {
+ int install_path_len = strlen(install_path);
+ if (install_path[install_path_len-1] == '/')
+ install_path_len--;
+
+ client_input->install_path = (char *)calloc(install_path_len+1, sizeof(char));
+ if (client_input->install_path)
+ strncpy(client_input->install_path, install_path, install_path_len);
+ }
+
+ if (file_name) {
+ client_input->file_name = (char *)calloc(strlen(file_name)+1, sizeof(char));
+ if (client_input->file_name)
+ strncpy(client_input->file_name, file_name, strlen(file_name));
+ }
+
+ if (etag) {
+ client_input->etag = (char *)calloc(strlen(etag)+1, sizeof(char));
+ if (client_input->etag)
+ strncpy(client_input->etag, etag, strlen(etag));
+
+ }
+
+ if (temp_file_path) {
+ client_input->temp_file_path = (char *)calloc(strlen(temp_file_path)+1, sizeof(char));
+ if (client_input->temp_file_path)
+ strncpy(client_input->temp_file_path, temp_file_path, strlen(temp_file_path));
+ }
+
+ if (pkg_name) {
+ client_input->pkg_name = (char *)calloc(strlen(pkg_name)+1, sizeof(char));
+ if (client_input->pkg_name)
+ strncpy(client_input->pkg_name, pkg_name, strlen(pkg_name));
+ }
+ client_input_basic = &(client_input->client_input_basic);
+ client_input_basic->req_url = (char *)calloc(strlen(url)+1, sizeof(char));
+ if(DA_NULL == client_input_basic->req_url) {
+ DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ }
+ strncpy(client_input_basic->req_url ,url,strlen(url));
+
+ if (request_header_count > 0) {
+ int i = 0;
+ client_input_basic->user_request_header =
+ (char **)calloc(1, sizeof(char *)*request_header_count);
+ if(DA_NULL == client_input_basic->user_request_header) {
+ DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ }
+ for (i = 0; i < request_header_count; i++)
+ {
+ client_input_basic->user_request_header[i] = strdup(request_header[i]);
+ }
+ client_input_basic->user_request_header_count = request_header_count;
+ }
+ }
+
+ thread_info = (download_thread_input *)calloc(1, sizeof(download_thread_input));
+ if (!thread_info) {
+ DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ } else {
+ thread_info->slot_id = slot_id;
+ thread_info->client_input = client_input;
+ }
+ if (pthread_attr_init(&thread_attr) != 0) {
+ ret = DA_ERR_FAIL_TO_CREATE_THREAD;
+ goto ERR;
+ }
+
+ if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED) != 0) {
+ ret = DA_ERR_FAIL_TO_CREATE_THREAD;
+ goto ERR;
+ }
+
+ if (pthread_create(&GET_DL_THREAD_ID(slot_id), &thread_attr,
+ __thread_start_download, thread_info) < 0) {
+ DA_LOG_ERR(Thread, "making thread failed..");
+ ret = DA_ERR_FAIL_TO_CREATE_THREAD;
+ } else {
+ if (GET_DL_THREAD_ID(slot_id) < 1) {
+ DA_LOG_ERR(Thread, "The thread start is failed before calling this");
+// When http resource is leaked, the thread ID is initialized at error handling section of thread_start_download()
+// Because the thread ID is initialized, the ptrhead_detach should not be called. This is something like timing issue between threads.
+// thread info and basic_dl_input is freed at thread_start_download(). And it should not returns error code in this case.
+ goto ERR;
+ }
+ }
+ DA_LOG_DEBUG(Thread, "download thread create slot_id[%d] thread id[%lu]",
+ slot_id,GET_DL_THREAD_ID(slot_id));
+
+ERR:
+ if (DA_RESULT_OK != ret) {
+ if (client_input) {
+ clean_up_client_input_info(client_input);
+ free(client_input);
+ client_input = DA_NULL;
+ }
+ if (thread_info) {
+ free(thread_info);
+ thread_info = DA_NULL;
+ }
+ destroy_download_info(slot_id);
+ }
+ return ret;
+}
+
+da_result_t __make_source_info_basic_download(
+ stage_info *stage,
+ client_input_t *client_input)
+{
+ da_result_t ret = DA_RESULT_OK;
+ client_input_basic_t *client_input_basic = DA_NULL;
+ source_info_t *source_info = DA_NULL;
+ source_info_basic_t *source_info_basic = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ if (!stage) {
+ DA_LOG_ERR(Default, "no stage; DA_ERR_INVALID_ARGUMENT");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+
+ client_input_basic = &(client_input->client_input_basic);
+ if (DA_NULL == client_input_basic->req_url) {
+ DA_LOG_ERR(Default, "DA_ERR_INVALID_URL");
+ ret = DA_ERR_INVALID_URL;
+ goto ERR;
+ }
+
+ source_info_basic = (source_info_basic_t*)calloc(1, sizeof(source_info_basic_t));
+ if (DA_NULL == source_info_basic) {
+ DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ }
+
+ source_info_basic->url = client_input_basic->req_url;
+ client_input_basic->req_url = DA_NULL;
+
+ if (client_input_basic->user_request_header) {
+ source_info_basic->user_request_header =
+ client_input_basic->user_request_header;
+ source_info_basic->user_request_header_count =
+ client_input_basic->user_request_header_count;
+ client_input_basic->user_request_header = DA_NULL;
+ client_input_basic->user_request_header_count = 0;
+ }
+
+ source_info = GET_STAGE_SOURCE_INFO(stage);
+ memset(source_info, 0, sizeof(source_info_t));
+
+ source_info->source_info_type.source_info_basic = source_info_basic;
+
+// DA_SECURE_LOGI("BASIC HTTP STARTED: URL=%s",
+// source_info->source_info_type.source_info_basic->url);
+ERR:
+ return ret;
+}
+
+void __thread_clean_up_handler_for_start_download(void *arg)
+{
+ DA_LOG_CRITICAL(Default, "cleanup for thread id = %d", pthread_self());
+}
+
+static void *__thread_start_download(void *data)
+{
+ da_result_t ret = DA_RESULT_OK;
+ download_thread_input *thread_info = DA_NULL;
+ client_input_t *client_input = DA_NULL;
+ stage_info *stage = DA_NULL;
+ download_state_t download_state = 0;
+
+ int slot_id = DA_INVALID_ID;
+
+ DA_LOG_FUNC_LOGV(Thread);
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, DA_NULL);
+
+ thread_info = (download_thread_input*)data;
+ if (DA_NULL == thread_info) {
+ DA_LOG_ERR(Thread, "thread_info is NULL..");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ return DA_NULL;
+ } else {
+ slot_id = thread_info->slot_id;
+ client_input = thread_info->client_input;
+
+ if(thread_info) {
+ free(thread_info);
+ thread_info = DA_NULL;
+ }
+ }
+
+ pthread_cleanup_push(__thread_clean_up_handler_for_start_download, (void *)NULL);
+
+ if (DA_FALSE == is_valid_slot_id(slot_id)) {
+ ret = DA_ERR_INVALID_ARGUMENT;
+ DA_LOG_ERR(Default, "Invalid Download ID");
+ goto ERR;
+ }
+
+ if (!client_input) {
+ ret = DA_ERR_INVALID_ARGUMENT;
+ DA_LOG_ERR(Default, "Invalid client_input");
+ goto ERR;
+ }
+
+ stage = Add_new_download_stage(slot_id);
+ if (!stage) {
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ DA_LOG_ERR(Default, "STAGE ADDITION FAIL!");
+ goto ERR;
+ }
+ DA_LOG_VERBOSE(Default, "new added Stage : %p", stage);
+
+ GET_DL_USER_DATA(slot_id) = client_input->user_data;
+ client_input->user_data = DA_NULL;
+ GET_DL_USER_INSTALL_PATH(slot_id) = client_input->install_path;
+ client_input->install_path = DA_NULL;
+ GET_DL_USER_FILE_NAME(slot_id) = client_input->file_name;
+ client_input->file_name = DA_NULL;
+ GET_DL_USER_ETAG(slot_id) = client_input->etag;
+ client_input->etag = DA_NULL;
+ GET_DL_USER_TEMP_FILE_PATH(slot_id) = client_input->temp_file_path;
+ client_input->temp_file_path = DA_NULL;
+
+ ret = __make_source_info_basic_download(stage, client_input);
+
+ if (ret == DA_RESULT_OK) {
+ /* to save memory */
+ if (client_input) {
+ clean_up_client_input_info(client_input);
+ free(client_input);
+ client_input = DA_NULL;
+ }
+
+ ret = __download_content(stage);
+ if (stage != GET_DL_CURRENT_STAGE(slot_id)) {
+ DA_LOG_ERR(Default,"Playready download case. The next stage is present stage");
+ stage = GET_DL_CURRENT_STAGE(slot_id);
+ }
+ }
+ERR:
+ if (client_input) {
+ clean_up_client_input_info(client_input);
+ free(client_input);
+ client_input = DA_NULL;
+ }
+
+ if (DA_RESULT_OK == ret) {
+ char *installed_path = NULL;
+ char *etag = DA_NULL;
+ req_dl_info *request_info = NULL;
+ file_info *file_storage = NULL;
+ DA_LOG_VERBOSE(Default, "Whole download flow is finished.");
+ _da_thread_mutex_lock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
+ download_state = GET_DL_STATE_ON_STAGE(stage);
+ _da_thread_mutex_unlock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
+ if (download_state == DOWNLOAD_STATE_ABORTED) {
+ DA_LOG(Default, "Abort case. Do not call client callback");
+#ifdef PAUSE_EXIT
+ } else if (download_state == DOWNLOAD_STATE_PAUSED) {
+ DA_LOG(Default, "Finish case from paused state");
+ destroy_download_info(slot_id);
+#endif
+ } else {
+ request_info = GET_STAGE_TRANSACTION_INFO(stage);
+ etag = GET_REQUEST_HTTP_HDR_ETAG(request_info);
+ file_storage = GET_STAGE_CONTENT_STORE_INFO(stage);
+ installed_path = GET_CONTENT_STORE_ACTUAL_FILE_NAME(file_storage);
+ send_user_noti_and_finish_download_flow(slot_id, installed_path,
+ etag);
+ }
+ } else {
+ char *etag = DA_NULL;
+ req_dl_info *request_info = NULL;
+ request_info = GET_STAGE_TRANSACTION_INFO(stage);
+ DA_LOG_CRITICAL(Default, "Download Failed -Return = %d", ret);
+ if (request_info) {
+ etag = GET_REQUEST_HTTP_HDR_ETAG(request_info);
+ send_client_finished_info(slot_id, GET_DL_ID(slot_id),
+ DA_NULL, etag, ret, get_http_status(slot_id));
+ }
+ destroy_download_info(slot_id);
+ }
+
+ pthread_cleanup_pop(0);
+ DA_LOG_CRITICAL(Thread, "==thread_start_download - EXIT==");
+ pthread_exit((void *)NULL);
+ return DA_NULL;
+}
+
+da_result_t __download_content(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ download_state_t download_state = 0;
+ da_bool_t isDownloadComplete = DA_FALSE;
+ int slot_id = DA_INVALID_ID;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ slot_id = GET_STAGE_DL_ID(stage);
+ CHANGE_DOWNLOAD_STATE(DOWNLOAD_STATE_NEW_DOWNLOAD, stage);
+
+ do {
+ stage = GET_DL_CURRENT_STAGE(slot_id);
+ _da_thread_mutex_lock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
+ download_state = GET_DL_STATE_ON_STAGE(stage);
+ DA_LOG_VERBOSE(Default, "download_state to - [%d] ", download_state);
+ _da_thread_mutex_unlock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
+
+ switch(download_state) {
+ case DOWNLOAD_STATE_NEW_DOWNLOAD:
+ ret = requesting_download(stage);
+
+ _da_thread_mutex_lock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
+ download_state = GET_DL_STATE_ON_STAGE(stage);
+ _da_thread_mutex_unlock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
+ if (download_state == DOWNLOAD_STATE_CANCELED ||
+ download_state == DOWNLOAD_STATE_ABORTED ||
+ download_state == DOWNLOAD_STATE_PAUSED) {
+ break;
+ } else {
+ if (DA_RESULT_OK == ret) {
+ ret = handle_after_download(stage);
+ }
+ }
+ break;
+ default:
+ isDownloadComplete = DA_TRUE;
+ break;
+ }
+ }while ((DA_RESULT_OK == ret) && (DA_FALSE == isDownloadComplete));
+
+ return ret;
+}
diff --git a/agent/download-agent-client-mgr.c b/agent/download-agent-client-mgr.c
new file mode 100755
index 0000000..b27a2d4
--- /dev/null
+++ b/agent/download-agent-client-mgr.c
@@ -0,0 +1,631 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <unistd.h>
+
+#include "download-agent-client-mgr.h"
+#include "download-agent-debug.h"
+#include "download-agent-utils.h"
+#include "download-agent-file.h"
+
+#define IS_CLIENT_Q_HAVING_DATA(QUEUE) (QUEUE->having_data)
+
+static client_app_mgr_t client_app_mgr;
+
+static da_result_t __launch_client_thread(void);
+static void *__thread_for_client_noti(void *data);
+void __thread_clean_up_handler_for_client_thread(void *arg);
+static void __pop_client_noti(client_noti_t **out_client_noti);
+
+void __client_q_goto_sleep_without_lock(void);
+void __client_q_wake_up_without_lock(void);
+void destroy_client_noti(client_noti_t *client_noti);
+
+da_result_t init_client_app_mgr()
+{
+ DA_LOG_FUNC_LOGV(ClientNoti);
+
+ if(client_app_mgr.is_init)
+ return DA_RESULT_OK;
+
+ client_app_mgr.is_init = DA_TRUE;
+ client_app_mgr.client_app_info.client_user_agent = DA_NULL;
+ client_app_mgr.is_thread_init = DA_FALSE;
+ client_app_mgr.thread_id = 0;
+
+ return DA_RESULT_OK;
+}
+
+da_bool_t is_client_app_mgr_init(void)
+{
+ return client_app_mgr.is_init;
+}
+
+da_result_t reg_client_app(
+ da_client_cb_t *da_client_callback)
+{
+ da_result_t ret = DA_RESULT_OK;
+ client_queue_t *queue = DA_NULL;
+ client_noti_t *client_noti = DA_NULL;
+
+ DA_LOG_FUNC_LOGD(ClientNoti);
+
+ memset(&(client_app_mgr.client_app_info.client_callback),
+ 0, sizeof(da_client_cb_t));
+ memcpy(&(client_app_mgr.client_app_info.client_callback),
+ da_client_callback, sizeof(da_client_cb_t));
+
+ _da_thread_mutex_init(&(client_app_mgr.mutex_client_mgr), DA_NULL);
+
+ /* If some noti is existed at queue, delete all */
+ do {
+ __pop_client_noti(&client_noti);
+ destroy_client_noti(client_noti);
+ } while(client_noti != DA_NULL);
+
+ queue = &(client_app_mgr.client_queue);
+ DA_LOG_VERBOSE(ClientNoti, "client queue = %p", queue);
+ _da_thread_mutex_init(&(queue->mutex_client_queue), DA_NULL);
+ _da_thread_cond_init(&(queue->cond_client_queue), DA_NULL);
+
+ ret = __launch_client_thread();
+
+ return ret;
+}
+
+da_result_t dereg_client_app(void)
+{
+ client_noti_t *client_noti = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(ClientNoti);
+
+ client_noti = (client_noti_t *)calloc(1, sizeof(client_noti_t));
+ if (!client_noti) {
+ DA_LOG_ERR(ClientNoti, "calloc fail");
+ return DA_ERR_FAIL_TO_MEMALLOC;
+ }
+
+ client_noti->slot_id = DA_INVALID_ID;
+ client_noti->noti_type = Q_CLIENT_NOTI_TYPE_TERMINATE;
+ client_noti->next = DA_NULL;
+
+ _da_thread_mutex_lock(&(client_app_mgr.mutex_client_mgr));
+ if (client_app_mgr.is_thread_init != DA_TRUE) {
+ DA_LOG_CRITICAL(ClientNoti, "try to cancel client mgr thread id[%lu]",
+ client_app_mgr.thread_id);
+ if (client_app_mgr.thread_id &&
+ pthread_cancel(client_app_mgr.thread_id) < 0) {
+ DA_LOG_ERR(ClientNoti, "cancel thread is failed!!!");
+ }
+ free(client_noti);
+ } else {
+ void *t_return = NULL;
+ DA_LOG_VERBOSE(ClientNoti, "pushing Q_CLIENT_NOTI_TYPE_TERMINATE");
+ push_client_noti(client_noti);
+ DA_LOG_DEBUG(Thread, "===try to join client mgr thread id[%lu]===",
+ client_app_mgr.thread_id);
+ if (client_app_mgr.thread_id &&
+ pthread_join(client_app_mgr.thread_id, &t_return) < 0) {
+ DA_LOG_ERR(Thread, "join client thread is failed!!!");
+ }
+ DA_LOG_DEBUG(Thread, "===thread join return[%d]===", (char*)t_return);
+ }
+ _da_thread_mutex_unlock(&(client_app_mgr.mutex_client_mgr));
+
+ /* ToDo: This clean up should be done at the end of client_thread. */
+ if(client_app_mgr.client_app_info.client_user_agent) {
+ free(client_app_mgr.client_app_info.client_user_agent);
+ client_app_mgr.client_app_info.client_user_agent = DA_NULL;
+ }
+ _da_thread_mutex_lock(&(client_app_mgr.mutex_client_mgr));
+ client_app_mgr.is_thread_init = DA_FALSE;
+ _da_thread_mutex_unlock(&(client_app_mgr.mutex_client_mgr));
+ _da_thread_mutex_destroy(&(client_app_mgr.mutex_client_mgr));
+ return DA_RESULT_OK;
+}
+
+da_result_t send_client_paused_info(int slot_id)
+{
+ client_noti_t *client_noti = DA_NULL;
+ user_paused_info_t *paused_info = DA_NULL;
+ download_state_t state = GET_DL_STATE_ON_ID(slot_id);
+
+ DA_LOG_FUNC_LOGD(ClientNoti);
+
+ if (!GET_DL_ENABLE_PAUSE_UPDATE(slot_id)) {
+ DA_LOG(ClientNoti, "Do not call pause cb");
+ return DA_RESULT_OK;
+ }
+ if (!is_valid_slot_id(slot_id)) {
+ DA_LOG_ERR(ClientNoti, "Download ID is not valid");
+ return DA_RESULT_OK;
+ }
+
+ DA_LOG_VERBOSE(ClientNoti, "slot_id[%d]", slot_id);
+ if ((DOWNLOAD_STATE_PAUSED != state)) {
+ DA_LOG(ClientNoti, "The state is not paused. state:%d", state);
+ return DA_ERR_INVALID_STATE;
+ }
+
+ client_noti = (client_noti_t *)calloc(1, sizeof(client_noti_t));
+ if (!client_noti) {
+ DA_LOG_ERR(ClientNoti, "calloc fail");
+ return DA_ERR_FAIL_TO_MEMALLOC;
+ }
+
+ client_noti->slot_id = slot_id;
+ client_noti->user_data = GET_DL_USER_DATA(slot_id);
+ client_noti->noti_type = Q_CLIENT_NOTI_TYPE_PAUSED_INFO;
+ client_noti->next = DA_NULL;
+
+ paused_info = (user_paused_info_t *)&(client_noti->type.paused_info);
+ paused_info->download_id= GET_DL_ID(slot_id);
+ DA_LOG(ClientNoti, "pushing paused info. slot_id=%d, dl_id=%d",
+ slot_id, GET_DL_ID(slot_id));
+
+ push_client_noti(client_noti);
+
+ return DA_RESULT_OK;
+}
+
+da_result_t send_client_update_progress_info (
+ int slot_id,
+ int dl_id,
+ unsigned long int received_size
+ )
+{
+ client_noti_t *client_noti = DA_NULL;
+ user_progress_info_t *progress_info = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(ClientNoti);
+
+ if (!is_valid_slot_id(slot_id)) {
+ DA_LOG_ERR(ClientNoti, "Download ID is not valid");
+ return DA_ERR_INVALID_DL_REQ_ID;
+ }
+
+ client_noti = (client_noti_t *)calloc(1, sizeof(client_noti_t));
+ if (!client_noti) {
+ DA_LOG_ERR(ClientNoti, "calloc fail");
+ return DA_ERR_FAIL_TO_MEMALLOC;
+ }
+
+ client_noti->slot_id = slot_id;
+ client_noti->user_data = GET_DL_USER_DATA(slot_id);
+ client_noti->noti_type = Q_CLIENT_NOTI_TYPE_PROGRESS_INFO;
+ client_noti->next = DA_NULL;
+
+ progress_info = (user_progress_info_t *)&(client_noti->type.update_progress_info);
+ progress_info->download_id= dl_id;
+ progress_info->received_size = received_size;
+
+ DA_LOG_VERBOSE(ClientNoti, "pushing received_size=%lu, slot_id=%d, dl_id=%d",
+ received_size, slot_id, dl_id);
+
+ push_client_noti(client_noti);
+
+ return DA_RESULT_OK;
+}
+
+da_result_t send_client_update_dl_info (
+ int slot_id,
+ int dl_id,
+ char *file_type,
+ unsigned long int file_size,
+ char *tmp_saved_path,
+ char *pure_file_name,
+ char *etag,
+ char *extension)
+{
+ client_noti_t *client_noti = DA_NULL;
+ user_download_info_t *update_dl_info = DA_NULL;
+ int len = 0;
+
+ DA_LOG_FUNC_LOGV(ClientNoti);
+
+ if (!is_valid_slot_id(slot_id)) {
+ DA_LOG_ERR(ClientNoti, "Download ID is not valid");
+ return DA_ERR_INVALID_DL_REQ_ID;
+ }
+
+ client_noti = (client_noti_t *)calloc(1, sizeof(client_noti_t));
+ if (!client_noti) {
+ DA_LOG_ERR(ClientNoti, "calloc fail");
+ return DA_ERR_FAIL_TO_MEMALLOC;
+ }
+
+ client_noti->slot_id = slot_id;
+ client_noti->user_data = GET_DL_USER_DATA(slot_id);
+ client_noti->noti_type = Q_CLIENT_NOTI_TYPE_STARTED_INFO;
+ client_noti->next = DA_NULL;
+
+ update_dl_info = (user_download_info_t *)&(client_noti->type.update_dl_info);
+ update_dl_info->download_id = dl_id;
+ update_dl_info->file_size = file_size;
+ if (pure_file_name && extension) {
+ len = strlen(pure_file_name) + strlen(extension) + 1;
+ update_dl_info->content_name = (char *)calloc(len + 1, sizeof(char));
+ if (!update_dl_info->content_name) {
+ free(client_noti);
+ return DA_ERR_FAIL_TO_MEMALLOC;
+ }
+ snprintf(update_dl_info->content_name, len + 1, "%s.%s",
+ pure_file_name, extension);
+ }
+
+ /* These strings MUST be copied to detach __thread_for_client_noti from download_info */
+ if (file_type)
+ update_dl_info->file_type = strdup(file_type);
+
+ if (tmp_saved_path)
+ update_dl_info->tmp_saved_path = strdup(tmp_saved_path);
+
+ if (etag)
+ update_dl_info->etag = strdup(etag);
+ DA_LOG_DEBUG(ClientNoti, "pushing slot_id=%d, dl_id=%d", slot_id, dl_id);
+
+ push_client_noti(client_noti);
+
+ return DA_RESULT_OK;
+}
+
+da_result_t send_client_finished_info (
+ int slot_id,
+ int dl_id,
+ char *saved_path,
+ char *etag,
+ int error,
+ int http_status
+ )
+{
+ client_noti_t *client_noti = DA_NULL;
+ user_finished_info_t *finished_info = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(ClientNoti);
+
+ if (!is_valid_slot_id(slot_id)) {
+ DA_LOG_ERR(ClientNoti, "Download ID is not valid");
+ return DA_ERR_INVALID_DL_REQ_ID;
+ }
+
+ client_noti = (client_noti_t *)calloc(1, sizeof(client_noti_t));
+ if (!client_noti) {
+ DA_LOG_ERR(ClientNoti, "calloc fail");
+ return DA_ERR_FAIL_TO_MEMALLOC;
+ }
+
+ client_noti->slot_id = slot_id;
+ client_noti->user_data = GET_DL_USER_DATA(slot_id);
+ client_noti->noti_type = Q_CLIENT_NOTI_TYPE_FINISHED_INFO;
+ client_noti->next = DA_NULL;
+
+ finished_info = (user_finished_info_t *)&(client_noti->type.finished_info);
+ finished_info->download_id = dl_id;
+ finished_info->err = error;
+ finished_info->http_status = http_status;
+
+ if (saved_path) {
+ finished_info->saved_path = strdup(saved_path);
+ DA_SECURE_LOGD("saved path=%s", saved_path);
+ }
+ if (etag) {
+ finished_info->etag = strdup(etag);
+ DA_SECURE_LOGD("pushing finished info. etag[%s]", etag);
+ }
+ DA_LOG_VERBOSE(ClientNoti, "user_data=%p", client_noti->user_data);
+ DA_LOG_VERBOSE(ClientNoti, "http_status=%d", http_status);
+ DA_LOG(ClientNoti, "pushing slot_id=%d, dl_id=%d err=%d", slot_id, dl_id, error);
+
+ push_client_noti(client_noti);
+
+ return DA_RESULT_OK;
+}
+
+da_result_t __launch_client_thread(void)
+{
+ pthread_t thread_id = 0;
+
+ DA_LOG_FUNC_LOGV(Thread);
+
+ if (pthread_create(&thread_id, DA_NULL,
+ __thread_for_client_noti,DA_NULL) < 0) {
+ DA_LOG_ERR(Thread, "making thread failed..");
+ return DA_ERR_FAIL_TO_CREATE_THREAD;
+ }
+ DA_LOG_VERBOSE(Thread, "client mgr thread id[%d]", thread_id);
+ client_app_mgr.thread_id = thread_id;
+ return DA_RESULT_OK;
+}
+
+void destroy_client_noti(client_noti_t *client_noti)
+{
+ if (client_noti) {
+ if (client_noti->noti_type == Q_CLIENT_NOTI_TYPE_STARTED_INFO) {
+ user_download_info_t *update_dl_info = DA_NULL;
+ update_dl_info = (user_download_info_t*)&(client_noti->type.update_dl_info);
+ if (update_dl_info->file_type) {
+ free(update_dl_info->file_type);
+ update_dl_info->file_type = DA_NULL;
+ }
+ if (update_dl_info->tmp_saved_path) {
+ free(update_dl_info->tmp_saved_path);
+ update_dl_info->tmp_saved_path = DA_NULL;
+ }
+ if (update_dl_info->etag) {
+ free(update_dl_info->etag);
+ update_dl_info->etag = DA_NULL;
+ }
+ } else if (client_noti->noti_type ==
+ Q_CLIENT_NOTI_TYPE_FINISHED_INFO) {
+ user_finished_info_t *finished_info = DA_NULL;
+ finished_info = (user_finished_info_t*)
+ &(client_noti->type.finished_info);
+ if (finished_info->saved_path) {
+ free(finished_info->saved_path);
+ finished_info->saved_path = DA_NULL;
+ }
+ if (finished_info->etag) {
+ free(finished_info->etag);
+ finished_info->etag = DA_NULL;
+ }
+ }
+ free(client_noti);
+ }
+}
+
+
+void push_client_noti(client_noti_t *client_noti)
+{
+ client_queue_t *queue = DA_NULL;
+ client_noti_t *head = DA_NULL;
+ client_noti_t *pre = DA_NULL;
+ client_noti_t *cur = DA_NULL;
+
+ queue = &(client_app_mgr.client_queue);
+ _da_thread_mutex_lock (&(queue->mutex_client_queue));
+
+ head = queue->client_q_head;
+ if (!head) {
+ queue->client_q_head = client_noti;
+ } else {
+ cur = head;
+ while (cur->next) {
+ pre = cur;
+ cur = pre->next;
+ }
+#if 0
+ if (cur->noti_type == Q_CLIENT_NOTI_TYPE_PROGRESS_INFO) {
+ /* For UI performance. If the update noti info is existed at queue,
+ replace it with new update noti info */
+ if (cur->slot_id == client_noti->slot_id) {
+ /* DA_LOG(ClientNoti, "exchange queue's tail and pushing item"); */
+ if (pre == DA_NULL)
+ queue->client_q_head = client_noti;
+ else
+ pre->next = client_noti;
+ destroy_client_noti(cur);
+ } else {
+ cur->next = client_noti;
+ }
+ } else {
+ cur->next = client_noti;
+ }
+#else
+ cur->next = client_noti;
+#endif
+ }
+
+ queue->having_data = DA_TRUE;
+
+ __client_q_wake_up_without_lock();
+ if (queue->client_q_head->next) {
+ DA_LOG_VERBOSE(ClientNoti, "client noti[%p] next noti[%p]",
+ queue->client_q_head, queue->client_q_head->next);
+ } else {
+ DA_LOG_VERBOSE(ClientNoti, "client noti[%p] next noti is NULL",
+ queue->client_q_head);
+ }
+
+ _da_thread_mutex_unlock (&(queue->mutex_client_queue));
+}
+
+void __pop_client_noti(client_noti_t **out_client_noti)
+{
+ client_queue_t *queue = DA_NULL;
+
+ queue = &(client_app_mgr.client_queue);
+
+ _da_thread_mutex_lock (&(queue->mutex_client_queue));
+
+ if (queue->client_q_head) {
+ *out_client_noti = queue->client_q_head;
+ queue->client_q_head = queue->client_q_head->next;
+ if (queue->client_q_head) {
+ DA_LOG_VERBOSE(ClientNoti, "client noti[%p] next noti[%p]",
+ *out_client_noti, queue->client_q_head);
+ } else {
+ DA_LOG_VERBOSE(ClientNoti, "client noti[%p] next noti is NULL",
+ *out_client_noti);
+ }
+ } else {
+ *out_client_noti = DA_NULL;
+ }
+
+ if (queue->client_q_head == DA_NULL) {
+ queue->having_data = DA_FALSE;
+ }
+
+ _da_thread_mutex_unlock (&(queue->mutex_client_queue));
+}
+
+void __client_q_goto_sleep_without_lock(void)
+{
+ client_queue_t *queue = DA_NULL;
+ queue = &(client_app_mgr.client_queue);
+ _da_thread_cond_wait(&(queue->cond_client_queue), &(queue->mutex_client_queue));
+}
+
+void __client_q_wake_up_without_lock(void)
+{
+ client_queue_t *queue = DA_NULL;
+ queue = &(client_app_mgr.client_queue);
+ _da_thread_cond_signal(&(queue->cond_client_queue));
+}
+
+void __thread_clean_up_handler_for_client_thread(void *arg)
+{
+ DA_LOG_CRITICAL(Thread, "cleanup for thread id = %d", pthread_self());
+}
+
+static void *__thread_for_client_noti(void *data)
+{
+ da_result_t ret = DA_RESULT_OK;
+ da_bool_t need_wait = DA_TRUE;
+ client_queue_t *queue = DA_NULL;
+ client_noti_t *client_noti = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(Thread);
+
+ _da_thread_mutex_lock(&(client_app_mgr.mutex_client_mgr));
+ client_app_mgr.is_thread_init = DA_TRUE;
+ _da_thread_mutex_unlock(&(client_app_mgr.mutex_client_mgr));
+
+ queue = &(client_app_mgr.client_queue);
+ DA_LOG_VERBOSE(ClientNoti, "client queue = %p", queue);
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, DA_NULL);
+ pthread_cleanup_push(__thread_clean_up_handler_for_client_thread, (void *)DA_NULL);
+
+ do {
+ _da_thread_mutex_lock(&(queue->mutex_client_queue));
+ if (DA_FALSE == IS_CLIENT_Q_HAVING_DATA(queue)) {
+ DA_LOG_VERBOSE(Thread, "Sleep @ thread_for_client_noti!");
+ __client_q_goto_sleep_without_lock();
+ DA_LOG_VERBOSE(Thread, "Woke up @ thread_for_client_noti");
+ }
+ _da_thread_mutex_unlock(&(queue->mutex_client_queue));
+
+ do {
+ __pop_client_noti(&client_noti);
+ if (client_noti == DA_NULL) {
+ DA_LOG_ERR(ClientNoti, "There is no data on client queue!");
+ ret = DA_ERR_INVALID_STATE;
+ need_wait = DA_FALSE;
+ } else {
+ DA_LOG_VERBOSE(ClientNoti, "noti type[%d]",
+ client_noti->noti_type);
+ switch (client_noti->noti_type) {
+ case Q_CLIENT_NOTI_TYPE_STARTED_INFO:
+ {
+ user_download_info_t *update_dl_info = DA_NULL;;
+ update_dl_info = (user_download_info_t*)(&(client_noti->type.update_dl_info));
+ if (client_app_mgr.client_app_info.client_callback.update_dl_info_cb) {
+ client_app_mgr.client_app_info.client_callback.update_dl_info_cb(update_dl_info, client_noti->user_data);
+ if (update_dl_info->etag)
+ DA_SECURE_LOGD("Etag:[%s]", update_dl_info->etag);
+ DA_SECURE_LOGD("file size=%lu", update_dl_info->file_size);
+ DA_LOG(ClientNoti, "Update download info for slot_id=%d, dl_id=%d- DONE",
+ client_noti->slot_id,
+ update_dl_info->download_id
+ );
+ }
+ }
+ break;
+ case Q_CLIENT_NOTI_TYPE_PROGRESS_INFO:
+ {
+ user_progress_info_t *progress_info = DA_NULL;;
+ progress_info = (user_progress_info_t*)(&(client_noti->type.update_progress_info));
+ if (client_app_mgr.client_app_info.client_callback.update_progress_info_cb) {
+ client_app_mgr.client_app_info.client_callback.update_progress_info_cb(progress_info, client_noti->user_data);
+ DA_LOG_VERBOSE(ClientNoti, "Update downloading info for slot_id=%d, dl_id=%d, received size=%lu - DONE",
+ client_noti->slot_id,
+ progress_info->download_id,
+ progress_info->received_size);
+ }
+ }
+ break;
+ case Q_CLIENT_NOTI_TYPE_FINISHED_INFO:
+ {
+ user_finished_info_t *finished_info = DA_NULL;;
+ finished_info = (user_finished_info_t*)(&(client_noti->type.finished_info));
+ if (client_app_mgr.client_app_info.client_callback.finished_info_cb) {
+ client_app_mgr.client_app_info.client_callback.finished_info_cb(
+ finished_info, client_noti->user_data);
+ DA_LOG(ClientNoti, "Completed info for slot_id=%d, dl_id=%d, err=%d http_state=%d user_data=%p- DONE",
+ client_noti->slot_id,
+ finished_info->download_id,
+ finished_info->err,
+ finished_info->http_status,
+ client_noti->user_data);
+ if (finished_info->etag)
+ DA_SECURE_LOGD("Completed info for etag=%s - DONE",
+ finished_info->etag);
+
+ }
+ }
+ break;
+ case Q_CLIENT_NOTI_TYPE_PAUSED_INFO:
+ {
+ user_paused_info_t *da_paused_info = DA_NULL;
+ da_paused_info = (user_paused_info_t *)(&(client_noti->type.paused_info));
+
+ if (client_app_mgr.client_app_info.client_callback.paused_info_cb) {
+ DA_LOG(ClientNoti, "User Paused info for slot_id=%d, dl_id=%d - Done",
+ client_noti->slot_id,
+ da_paused_info->download_id);
+ client_app_mgr.client_app_info.client_callback.paused_info_cb(
+ da_paused_info, client_noti->user_data);
+ }
+ }
+ break;
+ case Q_CLIENT_NOTI_TYPE_TERMINATE:
+ DA_LOG_VERBOSE(ClientNoti, "Q_CLIENT_NOTI_TYPE_TERMINATE");
+ need_wait = DA_FALSE;
+ break;
+ }
+ destroy_client_noti(client_noti);
+ }
+
+ if(DA_TRUE == need_wait) {
+ _da_thread_mutex_lock(&(queue->mutex_client_queue));
+ if (DA_FALSE == IS_CLIENT_Q_HAVING_DATA(queue)) {
+ _da_thread_mutex_unlock (&(queue->mutex_client_queue));
+ break;
+ } else {
+ _da_thread_mutex_unlock (&(queue->mutex_client_queue));
+ }
+ } else {
+ break;
+ }
+ } while (1);
+ } while (DA_TRUE == need_wait);
+
+ _da_thread_mutex_destroy(&(queue->mutex_client_queue));
+ _da_thread_cond_destroy(&(queue->cond_client_queue));
+
+ pthread_cleanup_pop(0);
+ DA_LOG_DEBUG(Thread, "=====thread_for_client_noti- EXIT=====");
+ pthread_exit((void *)NULL);
+ return DA_NULL;
+}
+
+char *get_client_user_agent_string(void)
+{
+ if (!client_app_mgr.is_init)
+ return DA_NULL;
+
+ return client_app_mgr.client_app_info.client_user_agent;
+}
diff --git a/agent/download-agent-debug.c b/agent/download-agent-debug.c
new file mode 100755
index 0000000..07078b3
--- /dev/null
+++ b/agent/download-agent-debug.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include "download-agent-debug.h"
+#include "download-agent-utils.h"
+
+#define STRING_IT(x) #x
+#define TURN_ON_LOG(channel) (DALogBitMap |= (0x1<<(channel)))
+
+int DALogBitMap;
+
+char *__get_log_env(void);
+char **__parsing_log_env(char *in_log_env);
+char *__copying_str(char *source, int length);
+char *__get_channel_name_from_enum(da_log_channel channel_enum);
+
+da_result_t init_log_mgr(void) {
+ da_result_t ret = DA_RESULT_OK;
+ static da_bool_t did_log_mgr_init = DA_FALSE;
+ char *log_env = DA_NULL;
+ char **parsed_log_env = DA_NULL;
+ char **cur_parsed_log_env = DA_NULL;
+ int i = 0;
+
+ if (did_log_mgr_init)
+ return ret;
+
+ did_log_mgr_init = DA_TRUE;
+
+ log_env = __get_log_env();
+ if (!log_env) {
+ /* If no environment values are found, do behave like all logs are turned on except for Soup log */
+ DALogBitMap = ~(0x1 << Soup);
+ return ret;
+ }
+
+ TURN_ON_LOG(Default);
+
+ parsed_log_env = __parsing_log_env(log_env);
+ if (parsed_log_env) {
+ char *channel_keyward = DA_NULL;
+ for (cur_parsed_log_env = parsed_log_env; *cur_parsed_log_env; cur_parsed_log_env++) {
+ if (!*cur_parsed_log_env)
+ break;
+ for (i = 0; i < DA_LOG_CHANNEL_MAX; i++) {
+ channel_keyward = __get_channel_name_from_enum(i);
+ if (channel_keyward && !strcmp(*cur_parsed_log_env,
+ channel_keyward)) {
+ TURN_ON_LOG(i);
+ break;
+ }
+ }
+ free(*cur_parsed_log_env);
+ }
+ free(parsed_log_env);
+ }
+
+ if (log_env)
+ free(log_env);
+
+ return ret;
+}
+
+char *__get_log_env(void) {
+ char *log_env = DA_NULL;
+
+ /* environment value has higher priority than configure file */
+ log_env = getenv(DA_DEBUG_ENV_KEY);
+ if (log_env && strlen(log_env))
+ return strdup(log_env);
+
+ if (read_data_from_file(DA_DEBUG_CONFIG_FILE_PATH, &log_env))
+ return log_env;
+
+ return DA_NULL;
+}
+
+char **__parsing_log_env(char *in_log_env) {
+ char **out_parsed_result = DA_NULL;
+
+ char **temp_result_array = DA_NULL;
+ char **cur_temp_result_array = DA_NULL;
+ int how_many_item = 0;
+ int how_many_delimeter = 0;
+
+ char delimiter = ',';
+
+ char *org_str = in_log_env;
+ char *cur_char = org_str;
+ char *start = org_str;
+ char *end = org_str;
+ int target_len = 0;
+
+ if (!org_str)
+ return DA_NULL;
+
+ /* counting delimiter to know how many items should be memory allocated.
+ * This causes two round of loop (counting delimiter and real operation).
+ * But I think it is tolerable, because input parameter is from console.
+ * And it is also a reason why we should not use fixed length array.
+ * Users are hard to input very long environment, but it is possible. */
+ for (cur_char = org_str; *cur_char; cur_char++) {
+ if (*cur_char == delimiter)
+ how_many_delimeter++;
+ }
+ how_many_item = how_many_delimeter + 1;
+ temp_result_array = (char**) calloc(1, how_many_item + 1);
+ if (!(temp_result_array))
+ goto ERR;
+
+ cur_temp_result_array = temp_result_array;
+ cur_char = org_str;
+ while (1) {
+ if (*cur_char == delimiter) {
+ end = cur_char;
+ target_len = (int) (end - start);
+ *cur_temp_result_array++ = __copying_str(start,
+ target_len);
+ start = ++cur_char;
+ continue;
+ } else if (!(*cur_char)) {
+ end = cur_char;
+ target_len = (int) (end - start);
+ *cur_temp_result_array++ = __copying_str(start,
+ target_len);
+ *cur_temp_result_array = DA_NULL;
+ break;
+ } else {
+ cur_char++;
+ }
+ }
+ out_parsed_result = temp_result_array;
+ERR:
+ return out_parsed_result;
+}
+
+char *__copying_str(char *source, int length) {
+ char *copied_str = DA_NULL;
+ char *cur_pos = DA_NULL;
+ char white_space = ' ';
+ char end_of_line = 10; /* ASCII for LF */
+ int i = 0;
+
+ if (!source || !(length > 0))
+ return DA_NULL;
+
+ copied_str = (char*) calloc(1, length + 1);
+ if (copied_str) {
+ cur_pos = copied_str;
+ for (i = 0; i < length; i++) {
+ if ((source[i] != white_space) && (source[i]
+ != end_of_line))
+ *cur_pos++ = source[i];
+ }
+ }
+
+ return copied_str;
+}
+
+char *__get_channel_name_from_enum(da_log_channel channel_enum) {
+ switch (channel_enum) {
+ case Soup:
+ return STRING_IT(Soup);
+ case HTTPManager:
+ return STRING_IT(HTTPManager);
+ case FileManager:
+ return STRING_IT(FileManager);
+ case DRMManager:
+ return STRING_IT(DRMManager);
+ case DownloadManager:
+ return STRING_IT(DownloadManager);
+ case ClientNoti:
+ return STRING_IT(ClientNoti);
+ case HTTPMessageHandler:
+ return STRING_IT(HTTPMessageHandler);
+ case Encoding:
+ return STRING_IT(Encoding);
+ case QueueManager:
+ return STRING_IT(QueueManager);
+ case Parsing:
+ return STRING_IT(Parsing);
+ case Thread:
+ return STRING_IT(Thread);
+ case Default:
+ return STRING_IT(Default);
+ default:
+ return DA_NULL;
+ }
+}
diff --git a/agent/download-agent-dl-info-util.c b/agent/download-agent-dl-info-util.c
new file mode 100755
index 0000000..2b66357
--- /dev/null
+++ b/agent/download-agent-dl-info-util.c
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <string.h>
+
+#include "download-agent-client-mgr.h"
+#include "download-agent-dl-info-util.h"
+#include "download-agent-debug.h"
+#include "download-agent-utils.h"
+#include "download-agent-file.h"
+#include "download-agent-http-mgr.h"
+#include "download-agent-plugin-conf.h"
+
+pthread_mutex_t mutex_download_state[DA_MAX_DOWNLOAD_ID];
+static pthread_mutex_t mutex_download_mgr = PTHREAD_MUTEX_INITIALIZER;
+download_mgr_t download_mgr;
+
+void cleanup_source_info_basic_download(source_info_basic_t *source_info_basic);
+void cleanup_req_dl_info_http(req_dl_info *http_download);
+void destroy_file_info(file_info *file);
+
+da_result_t init_download_mgr() {
+ da_result_t ret = DA_RESULT_OK;
+ int i = 0;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ _da_thread_mutex_lock(&mutex_download_mgr);
+
+ if (download_mgr.is_init == DA_FALSE) {
+ download_mgr.is_init = DA_TRUE;
+
+ for (i = 0; i < DA_MAX_DOWNLOAD_ID; i++) {
+ _da_thread_mutex_init(&mutex_download_state[i], DA_NULL);
+ init_download_info(i);
+ }
+ init_dl_id_history(&(download_mgr.dl_id_history));
+ }
+
+ _da_thread_mutex_unlock(&mutex_download_mgr);
+
+ return ret;
+}
+
+da_result_t deinit_download_mgr(void) {
+ da_result_t ret = DA_RESULT_OK;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ _da_thread_mutex_lock(&mutex_download_mgr);
+ if (download_mgr.is_init == DA_TRUE) {
+ int i = 0;
+ dl_info_t *dl_info = DA_NULL;
+ void *t_return = NULL;
+ for (i = 0; i < DA_MAX_DOWNLOAD_ID; i++) {
+ dl_info = &(download_mgr.dl_info[i]);
+ if (dl_info && dl_info->is_using) {
+ request_to_abort_http_download(GET_DL_CURRENT_STAGE(i));
+ DA_LOG_CRITICAL(Thread, "===download id[%d] thread id[%lu] join===",i, GET_DL_THREAD_ID(i));
+/* Because the download daemon can call the deinit function, the resources of pthread are not freed
+ FIXME later : It is needed to change the termination flow again.
+ if (pthread_join(GET_DL_THREAD_ID(i), &t_return) < 0) {
+ DA_LOG_ERR(Thread, "join client thread is failed!!!");
+ }
+*/
+ DA_LOG_CRITICAL(Thread, "===download id[%d] thread join return[%d]===",i, (char*)t_return);
+ }
+ }
+ download_mgr.is_init = DA_FALSE;
+ deinit_dl_id_history(&(download_mgr.dl_id_history));
+ }
+ _da_thread_mutex_unlock(&mutex_download_mgr);
+ return ret;
+}
+
+void init_download_info(int slot_id)
+{
+ dl_info_t *dl_info = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ _da_thread_mutex_lock(&mutex_download_state[slot_id]);
+ dl_info = &(download_mgr.dl_info[slot_id]);
+ dl_info->is_using = DA_FALSE;
+ dl_info->state = DOWNLOAD_STATE_IDLE;
+ dl_info->download_stage_data = DA_NULL;
+ dl_info->dl_id = 0;
+ dl_info->http_status = 0;
+ dl_info->enable_pause_update = DA_FALSE;
+ dl_info->user_install_path = DA_NULL;
+ dl_info->user_file_name = DA_NULL;
+ dl_info->user_etag = DA_NULL;
+ dl_info->user_temp_file_path = DA_NULL;
+ dl_info->user_data = DA_NULL;
+
+ Q_init_queue(&(dl_info->queue));
+
+ DA_LOG_VERBOSE(Default, "Init slot_id [%d] Info END", slot_id);
+ _da_thread_mutex_unlock(&mutex_download_state[slot_id]);
+
+ return;
+}
+
+void destroy_download_info(int slot_id)
+{
+ dl_info_t *dl_info = DA_NULL;
+
+ DA_LOG_VERBOSE(Default, "Destroying slot_id [%d] Info", slot_id);
+
+ if (slot_id == DA_INVALID_ID) {
+ DA_LOG_ERR(Default, "invalid slot_id");
+ return;
+ }
+
+ dl_info = &(download_mgr.dl_info[slot_id]);
+ if (DA_FALSE == dl_info->is_using) {
+ return;
+ }
+
+ _da_thread_mutex_lock (&mutex_download_state[slot_id]);
+ dl_info->state = DOWNLOAD_STATE_IDLE;
+ dl_info->active_dl_thread_id = 0;
+
+ if (dl_info->download_stage_data != DA_NULL) {
+ remove_download_stage(slot_id, dl_info->download_stage_data);
+ dl_info->download_stage_data = DA_NULL;
+ }
+ dl_info->dl_id = 0;
+ dl_info->enable_pause_update = DA_FALSE;
+ if (dl_info->user_install_path) {
+ free(dl_info->user_install_path);
+ dl_info->user_install_path = DA_NULL;
+ }
+
+ if (dl_info->user_file_name) {
+ free(dl_info->user_file_name);
+ dl_info->user_file_name = DA_NULL;
+ }
+
+ if (dl_info->user_etag) {
+ free(dl_info->user_etag);
+ dl_info->user_etag = DA_NULL;
+ }
+
+ if (dl_info->user_temp_file_path) {
+ free(dl_info->user_temp_file_path);
+ dl_info->user_temp_file_path = DA_NULL;
+ }
+
+ dl_info->user_data = DA_NULL;
+
+ Q_destroy_queue(&(dl_info->queue));
+ dl_info->http_status = 0;
+
+ dl_info->is_using = DA_FALSE;
+
+ DA_LOG_DEBUG(Default, "Destroying slot_id [%d] Info END", slot_id);
+ _da_thread_mutex_unlock (&mutex_download_state[slot_id]);
+ return;
+}
+
+void *Add_new_download_stage(int slot_id)
+{
+ stage_info *download_stage_data = NULL;
+ stage_info *new_download_stage_data = NULL;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ new_download_stage_data = (stage_info*)calloc(1, sizeof(stage_info));
+ if (!new_download_stage_data)
+ goto ERR;
+
+ new_download_stage_data->dl_id = slot_id;
+ download_stage_data = GET_DL_CURRENT_STAGE(slot_id);
+ if (download_stage_data) {
+ while (download_stage_data->next_stage_info) {
+ download_stage_data
+ = download_stage_data->next_stage_info;
+ };
+ download_stage_data->next_stage_info = new_download_stage_data;
+ } else {
+ GET_DL_CURRENT_STAGE(slot_id) = new_download_stage_data;
+ }
+ DA_LOG_VERBOSE(Default, "NEW STAGE ADDED FOR DOWNLOAD ID[%d] new_stage[%p]", slot_id,new_download_stage_data);
+
+ERR:
+ return new_download_stage_data;
+}
+
+void remove_download_stage(int slot_id, stage_info *in_stage)
+{
+ stage_info *stage = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ stage = GET_DL_CURRENT_STAGE(slot_id);
+ if (DA_NULL == stage) {
+ DA_LOG_VERBOSE(Default, "There is no stage field on slot_id = %d", slot_id);
+ goto ERR;
+ }
+
+ if (DA_NULL == in_stage) {
+ DA_LOG_VERBOSE(Default, "There is no in_stage to remove.");
+ goto ERR;
+ }
+
+ if (in_stage == stage) {
+ DA_LOG_VERBOSE(Default, "Base stage will be removed. in_stage[%p]",in_stage);
+ DA_LOG_VERBOSE(Default, "next stage[%p]",stage->next_stage_info);
+ GET_DL_CURRENT_STAGE(slot_id) = stage->next_stage_info;
+ empty_stage_info(in_stage);
+ free(in_stage);
+ in_stage = DA_NULL;
+ } else {
+ while (in_stage != stage->next_stage_info) {
+ stage = stage->next_stage_info;
+ }
+ if (in_stage == stage->next_stage_info) {
+ stage->next_stage_info
+ = stage->next_stage_info->next_stage_info;
+ DA_LOG_VERBOSE(Default, "Stage will be removed. in_stage[%p]",in_stage);
+ DA_LOG_VERBOSE(Default, "next stage[%p]",stage->next_stage_info);
+ empty_stage_info(in_stage);
+ free(in_stage);
+ in_stage = DA_NULL;
+ }
+ }
+
+ERR:
+ return;
+}
+
+void empty_stage_info(stage_info *in_stage)
+{
+ source_info_t *source_information = NULL;
+ req_dl_info *request_download_info = NULL;
+ file_info *file_information = NULL;
+
+ DA_LOG_VERBOSE(Default, "Stage to Remove:[%p]", in_stage);
+ source_information = GET_STAGE_SOURCE_INFO(in_stage);
+
+ cleanup_source_info_basic_download(
+ GET_SOURCE_BASIC(source_information));
+
+ request_download_info = GET_STAGE_TRANSACTION_INFO(in_stage);
+
+ cleanup_req_dl_info_http(request_download_info);
+
+ file_information = GET_STAGE_CONTENT_STORE_INFO(in_stage);
+ destroy_file_info(file_information);
+}
+
+void cleanup_source_info_basic_download(source_info_basic_t *source_info_basic)
+{
+ if (NULL == source_info_basic)
+ goto ERR;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ if (NULL != source_info_basic->url) {
+ free(source_info_basic->url);
+ source_info_basic->url = DA_NULL;
+ }
+
+ERR:
+ return;
+
+}
+
+void cleanup_req_dl_info_http(req_dl_info *http_download)
+{
+ DA_LOG_FUNC_LOGV(Default);
+
+ if (http_download->http_info.http_msg_request) {
+ http_msg_request_destroy(
+ &(http_download->http_info.http_msg_request));
+ http_download->http_info.http_msg_request = DA_NULL;
+ }
+
+ if (http_download->http_info.http_msg_response) {
+ http_msg_response_destroy(
+ &(http_download->http_info.http_msg_response));
+ http_download->http_info.http_msg_response = DA_NULL;
+ }
+
+ if (DA_NULL != http_download->location_url) {
+ free(http_download->location_url);
+ http_download->location_url = DA_NULL;
+ }
+ if (DA_NULL != http_download->content_type_from_header) {
+ free(http_download->content_type_from_header);
+ http_download->content_type_from_header = DA_NULL;
+ }
+
+ if (DA_NULL != http_download->etag_from_header) {
+ free(http_download->etag_from_header);
+ http_download->etag_from_header = DA_NULL;
+ }
+
+ http_download->invloved_transaction_id = DA_INVALID_ID;
+ http_download->content_len_from_header = 0;
+ http_download->downloaded_data_size = 0;
+
+ _da_thread_mutex_destroy(&(http_download->mutex_http_state));
+
+ return;
+}
+
+void destroy_file_info(file_info *file_information)
+{
+ DA_LOG_FUNC_LOGV(Default);
+
+ if (!file_information)
+ return;
+
+ if (file_information->file_name_final) {
+ free(file_information->file_name_final);
+ file_information->file_name_final = NULL;
+ }
+
+ if (file_information->content_type) {
+ free(file_information->content_type);
+ file_information->content_type = NULL;
+ }
+
+ if (file_information->pure_file_name) {
+ free(file_information->pure_file_name);
+ file_information->pure_file_name = NULL;
+ }
+
+ if (file_information->extension) {
+ free(file_information->extension);
+ file_information->extension = NULL;
+ }
+ return;
+}
+
+void clean_up_client_input_info(client_input_t *client_input)
+{
+ DA_LOG_FUNC_LOGV(Default);
+
+ if (client_input) {
+ client_input->user_data = NULL;
+
+ if (client_input->install_path) {
+ free(client_input->install_path);
+ client_input->install_path = DA_NULL;
+ }
+
+ if (client_input->file_name) {
+ free(client_input->file_name);
+ client_input->file_name = DA_NULL;
+ }
+
+ if (client_input->etag) {
+ free(client_input->etag);
+ client_input->etag = DA_NULL;
+ }
+
+ if (client_input->temp_file_path) {
+ free(client_input->temp_file_path);
+ client_input->temp_file_path = DA_NULL;
+ }
+
+ if (client_input->pkg_name) {
+ free(client_input->pkg_name);
+ client_input->pkg_name = DA_NULL;
+ }
+
+ client_input_basic_t *client_input_basic =
+ &(client_input->client_input_basic);
+
+ if (client_input_basic && client_input_basic->req_url) {
+ free(client_input_basic->req_url);
+ client_input_basic->req_url = DA_NULL;
+ }
+
+ if (client_input_basic && client_input_basic->user_request_header) {
+ int i = 0;
+ int count = client_input_basic->user_request_header_count;
+ for (i = 0; i < count; i++)
+ {
+ if (client_input_basic->user_request_header[i]) {
+ free(client_input_basic->user_request_header[i]);
+ client_input_basic->user_request_header[i] = DA_NULL;
+ }
+ }
+
+ free(client_input_basic->user_request_header);
+ client_input_basic->user_request_header = DA_NULL;
+ client_input_basic->user_request_header_count = 0;
+ }
+ } else {
+ DA_LOG_ERR(Default, "client_input is NULL.");
+ }
+
+ return;
+}
+
+da_result_t get_slot_id_for_dl_id(
+ int dl_id,
+ int* slot_id)
+{
+ da_result_t ret = DA_ERR_INVALID_DL_REQ_ID;
+ int iter = 0;
+
+ if (dl_id < 0) {
+ DA_LOG_ERR(Default, "dl_id is less than 0 - %d", dl_id);
+ return DA_ERR_INVALID_DL_REQ_ID;
+ }
+
+ _da_thread_mutex_lock(&mutex_download_mgr);
+ for (iter = 0; iter < DA_MAX_DOWNLOAD_ID; iter++) {
+ if (download_mgr.dl_info[iter].is_using == DA_TRUE) {
+ if (download_mgr.dl_info[iter].dl_id ==
+ dl_id) {
+ *slot_id = iter;
+ ret = DA_RESULT_OK;
+ break;
+ }
+ }
+ }
+ _da_thread_mutex_unlock(&mutex_download_mgr);
+
+ return ret;
+}
+
+
+da_result_t get_available_slot_id(int *available_id)
+{
+ da_result_t ret = DA_ERR_ALREADY_MAX_DOWNLOAD;
+ int i;
+
+ _da_thread_mutex_lock(&mutex_download_mgr);
+ for (i = 0; i < DA_MAX_DOWNLOAD_ID; i++) {
+ if (download_mgr.dl_info[i].is_using == DA_FALSE) {
+ init_download_info(i);
+
+ download_mgr.dl_info[i].is_using = DA_TRUE;
+
+ download_mgr.dl_info[i].dl_id
+ = get_available_dl_id(&(download_mgr.dl_id_history));
+
+ *available_id = i;
+ DA_LOG_VERBOSE(Default, "available download id = %d", *available_id);
+ ret = DA_RESULT_OK;
+
+ break;
+ }
+ }
+ _da_thread_mutex_unlock(&mutex_download_mgr);
+
+ return ret;
+}
+
+da_bool_t is_valid_slot_id(int slot_id)
+{
+ da_bool_t ret = DA_FALSE;
+
+ if (slot_id >= 0 && slot_id < DA_MAX_DOWNLOAD_ID) {
+ if (download_mgr.dl_info[slot_id].is_using == DA_TRUE)
+ ret = DA_TRUE;
+ }
+
+ return ret;
+}
+
+void store_http_status(int dl_id, int status)
+{
+ if (status < 100 || status > 599) {
+ DA_LOG_ERR(Default, "Invalid status code [%d]", status);
+ return;
+ }
+ DA_LOG_VERBOSE(Default, "store_http_status id[%d]status[%d] ",dl_id, status);
+ download_mgr.dl_info[dl_id].http_status = status;
+}
+
+int get_http_status(int slot_id)
+{
+ if (!download_mgr.dl_info[slot_id].is_using) {
+ DA_LOG_ERR(Default, "Invalid slot_id [%d]", slot_id);
+ return 0;
+ }
+ return download_mgr.dl_info[slot_id].http_status;
+}
diff --git a/agent/download-agent-dl-mgr.c b/agent/download-agent-dl-mgr.c
new file mode 100755
index 0000000..7a2ce0d
--- /dev/null
+++ b/agent/download-agent-dl-mgr.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 "download-agent-client-mgr.h"
+#include "download-agent-debug.h"
+#include "download-agent-dl-mgr.h"
+#include "download-agent-utils.h"
+#include "download-agent-http-mgr.h"
+#include "download-agent-file.h"
+#include "download-agent-plugin-conf.h"
+
+
+static da_result_t __cancel_download_with_slot_id(int slot_id);
+static da_result_t __suspend_download_with_slot_id(int slot_id);
+
+
+da_result_t requesting_download(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ req_dl_info *request_session = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ if (!stage) {
+ DA_LOG_ERR(Default, "stage is null..");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+
+ ret = make_req_dl_info_http(stage, GET_STAGE_TRANSACTION_INFO(stage));
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ request_session = GET_STAGE_TRANSACTION_INFO(stage);
+ ret = request_http_download(stage);
+ if (DA_RESULT_OK == ret) {
+ DA_LOG_VERBOSE(Default, "Http download is complete.");
+ } else {
+ DA_LOG_ERR(Default, "Http download is failed. ret = %d", ret);
+ goto ERR;
+ }
+ERR:
+ return ret;
+}
+
+da_result_t handle_after_download(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ da_mime_type_id_t mime_type = DA_MIME_TYPE_NONE;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ mime_type = get_mime_type_id(
+ GET_CONTENT_STORE_CONTENT_TYPE(GET_STAGE_CONTENT_STORE_INFO(stage)));
+
+ switch (mime_type) {
+ case DA_MIME_TYPE_NONE:
+ DA_LOG(Default, "DA_MIME_TYPE_NONE");
+ ret = DA_ERR_MISMATCH_CONTENT_TYPE;
+ break;
+ default:
+ CHANGE_DOWNLOAD_STATE(DOWNLOAD_STATE_FINISH, stage);
+ break;
+ } /* end of switch */
+
+ return ret;
+}
+
+static da_result_t __cancel_download_with_slot_id(int slot_id)
+{
+ da_result_t ret = DA_RESULT_OK;
+ download_state_t download_state;
+ stage_info *stage = DA_NULL;
+
+ DA_LOG_FUNC_LOGD(Default);
+
+ _da_thread_mutex_lock (&mutex_download_state[slot_id]);
+ download_state = GET_DL_STATE_ON_ID(slot_id);
+ DA_LOG(Default, "download_state = %d", GET_DL_STATE_ON_ID(slot_id));
+
+ if (download_state == DOWNLOAD_STATE_FINISH ||
+ download_state == DOWNLOAD_STATE_CANCELED) {
+ DA_LOG_CRITICAL(Default, "Already download is finished. Do not send cancel request");
+ _da_thread_mutex_unlock (&mutex_download_state[slot_id]);
+ return ret;
+ }
+ _da_thread_mutex_unlock (&mutex_download_state[slot_id]);
+
+ stage = GET_DL_CURRENT_STAGE(slot_id);
+ if (!stage)
+ return DA_RESULT_OK;
+
+ ret = request_to_cancel_http_download(stage);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ DA_LOG(Default, "Download cancel Successful for download id - %d", slot_id);
+ERR:
+ return ret;
+}
+
+da_result_t cancel_download(int dl_id)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ int slot_id = DA_INVALID_ID;
+
+ DA_LOG_FUNC_LOGD(Default);
+
+ ret = get_slot_id_for_dl_id(dl_id, &slot_id);
+ if (ret != DA_RESULT_OK) {
+ DA_LOG_ERR(Default, "dl req ID is not Valid");
+ goto ERR;
+ }
+
+ if (DA_FALSE == is_valid_slot_id(slot_id)) {
+ DA_LOG_ERR(Default, "Download ID is not Valid");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+
+ ret = __cancel_download_with_slot_id(slot_id);
+
+ERR:
+ return ret;
+
+}
+
+static da_result_t __suspend_download_with_slot_id(int slot_id)
+{
+ da_result_t ret = DA_RESULT_OK;
+ download_state_t download_state;
+ stage_info *stage = DA_NULL;
+
+ DA_LOG_FUNC_LOGD(Default);
+
+ _da_thread_mutex_lock (&mutex_download_state[slot_id]);
+ download_state = GET_DL_STATE_ON_ID(slot_id);
+ DA_LOG(Default, "download_state = %d", GET_DL_STATE_ON_ID(slot_id));
+ _da_thread_mutex_unlock (&mutex_download_state[slot_id]);
+
+ stage = GET_DL_CURRENT_STAGE(slot_id);
+ if (!stage)
+ return DA_ERR_CANNOT_SUSPEND;
+
+ ret = request_to_suspend_http_download(stage);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ DA_LOG(Default, "Download Suspend Successful for download id-%d", slot_id);
+ERR:
+ return ret;
+}
+
+da_result_t suspend_download(int dl_id, da_bool_t is_enable_cb)
+{
+ da_result_t ret = DA_RESULT_OK;
+ int slot_id = DA_INVALID_ID;
+
+ DA_LOG_FUNC_LOGD(Default);
+
+ ret = get_slot_id_for_dl_id(dl_id, &slot_id);
+ if (ret != DA_RESULT_OK) {
+ DA_LOG_ERR(Default, "dl req ID is not Valid");
+ goto ERR;
+ }
+ GET_DL_ENABLE_PAUSE_UPDATE(slot_id) = is_enable_cb;
+ if (DA_FALSE == is_valid_slot_id(slot_id)) {
+ DA_LOG_ERR(Default, "Download ID is not Valid");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+
+ ret = __suspend_download_with_slot_id(slot_id);
+
+ERR:
+ return ret;
+
+}
+
+static da_result_t __resume_download_with_slot_id(int slot_id)
+{
+ da_result_t ret = DA_RESULT_OK;
+ download_state_t download_state;
+ stage_info *stage = DA_NULL;
+
+ DA_LOG_FUNC_LOGD(Default);
+
+ _da_thread_mutex_lock (&mutex_download_state[slot_id]);
+ download_state = GET_DL_STATE_ON_ID(slot_id);
+ DA_LOG(Default, "download_state = %d", GET_DL_STATE_ON_ID(slot_id));
+ _da_thread_mutex_unlock (&mutex_download_state[slot_id]);
+
+ stage = GET_DL_CURRENT_STAGE(slot_id);
+
+ ret = request_to_resume_http_download(stage);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ DA_LOG(Default, "Download Resume Successful for download id-%d", slot_id);
+ERR:
+ return ret;
+}
+
+da_result_t resume_download(int dl_id)
+{
+ da_result_t ret = DA_RESULT_OK;
+ int slot_id = DA_INVALID_ID;
+
+ DA_LOG_FUNC_LOGD(Default);
+
+ ret = get_slot_id_for_dl_id(dl_id, &slot_id);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ if (DA_FALSE == is_valid_slot_id(slot_id)) {
+ DA_LOG_ERR(Default, "Download ID is not Valid");
+ ret = DA_ERR_INVALID_DL_REQ_ID;
+ goto ERR;
+ }
+
+ ret = __resume_download_with_slot_id(slot_id);
+
+ERR:
+ return ret;
+}
+
+da_result_t send_user_noti_and_finish_download_flow(
+ int slot_id, char *installed_path, char *etag)
+{
+ da_result_t ret = DA_RESULT_OK;
+ download_state_t download_state = HTTP_STATE_READY_TO_DOWNLOAD;
+ da_bool_t need_destroy_download_info = DA_FALSE;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ _da_thread_mutex_lock (&mutex_download_state[slot_id]);
+ download_state = GET_DL_STATE_ON_ID(slot_id);
+ DA_LOG_DEBUG(Default, "state = %d", download_state);
+ _da_thread_mutex_unlock (&mutex_download_state[slot_id]);
+
+ switch (download_state) {
+ case DOWNLOAD_STATE_FINISH:
+ send_client_finished_info(slot_id, GET_DL_ID(slot_id),
+ installed_path, DA_NULL, DA_RESULT_OK,
+ get_http_status(slot_id));
+ need_destroy_download_info = DA_TRUE;
+ break;
+ case DOWNLOAD_STATE_CANCELED:
+ send_client_finished_info(slot_id, GET_DL_ID(slot_id),
+ installed_path, etag, DA_RESULT_USER_CANCELED,
+ get_http_status(slot_id));
+ need_destroy_download_info = DA_TRUE;
+ break;
+#ifdef PAUSE_EXIT
+ case DOWNLOAD_STATE_PAUSED:
+ need_destroy_download_info = DA_TRUE;
+ break;
+#endif
+ default:
+ DA_LOG(Default, "download state = %d", download_state);
+ break;
+ }
+
+ if (need_destroy_download_info == DA_TRUE) {
+ destroy_download_info(slot_id);
+ } else {
+ DA_LOG_CRITICAL(Default, "download info is not destroyed");
+ }
+
+ return ret;
+}
+
+da_bool_t is_valid_download_id(int dl_id)
+{
+
+ da_bool_t ret = DA_TRUE;
+ int slot_id = DA_INVALID_ID;
+
+ DA_LOG_VERBOSE(Default, "[is_valid_download_id]download_id : %d", dl_id);
+
+ ret = get_slot_id_for_dl_id(dl_id, &slot_id);
+ if (ret != DA_RESULT_OK) {
+ DA_LOG_ERR(Default, "dl req ID is not Valid");
+ ret = DA_FALSE;
+ goto ERR;
+ } else {
+ ret = DA_TRUE;
+ }
+
+ if (DA_FALSE == is_valid_slot_id(slot_id)) {
+ DA_LOG_ERR(Default, "Download ID is not Valid");
+ ret = DA_FALSE;
+ goto ERR;
+ }
+ if (GET_DL_THREAD_ID(slot_id) < 1) {
+ DA_LOG_ERR(Default, "Download thread is not alive");
+ ret = DA_FALSE;
+ goto ERR;
+ }
+
+ERR:
+ return ret;
+}
diff --git a/agent/download-agent-encoding.c b/agent/download-agent-encoding.c
new file mode 100755
index 0000000..1955fcd
--- /dev/null
+++ b/agent/download-agent-encoding.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <string.h>
+#include <stdlib.h>
+#include <glib.h>
+
+#include "download-agent-encoding.h"
+#include "download-agent-debug.h"
+
+da_result_t _parsing_base64_encoded_str(const char *in_encoded_str,
+ char **out_charset_type,
+ char *out_encoding_type,
+ char **out_raw_encoded_str);
+
+da_bool_t is_base64_encoded_word(const char *in_str)
+{
+ const char *haystack = DA_NULL;
+ char first_needle[8] = {0,};
+ char second_needle[8] = {0,};
+ char *found_str = DA_NULL;
+
+ if (!in_str) {
+ DA_LOG_ERR(Default, "input string is NULL");
+ return DA_FALSE;
+ }
+
+ haystack = in_str;
+ if (haystack[0] == '"') {
+ snprintf(first_needle, sizeof(first_needle), "%s", "\"=?"); // "=?
+ snprintf(second_needle, sizeof(second_needle), "%s", "?=\""); // ?="
+ } else {
+ snprintf(first_needle, sizeof(first_needle), "%s", "=?"); // =?
+ snprintf(second_needle, sizeof(second_needle), "%s", "?="); // ?=
+ }
+
+// DA_SECURE_LOGD("needle = [%s], haystack = [%s]", first_needle, haystack);
+
+ found_str = strstr(haystack, first_needle);
+ if (found_str) {
+ if (found_str == haystack) {
+// DA_SECURE_LOGD("Input string is starting with %s", needle);
+ haystack = haystack + strlen(haystack) - strlen(second_needle);
+// DA_SECURE_LOGD("second haystack is [%s]", haystack);
+ if(!strcmp(haystack, second_needle))
+ return DA_TRUE;
+ }
+ }
+ return DA_FALSE;
+}
+
+da_result_t decode_base64_encoded_str(const char *in_encoded_str,
+ char **out_decoded_ascii_str)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ const char *org_str = DA_NULL;
+ char *charset_type = NULL;
+ char encoding_type = '\0';
+ char *raw_encoded_str = NULL;
+ char *decoded_str = NULL;
+ const gchar *g_encoded_text = NULL;
+ guchar *g_decoded_text = NULL;
+ gsize g_decoded_text_len = 0;
+
+ DA_SECURE_LOGD("input str = [%s]", in_encoded_str);
+
+ org_str = in_encoded_str;
+ if(!org_str) {
+ DA_LOG_ERR(Default, "Input string is NULL");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+
+ ret = _parsing_base64_encoded_str(org_str, &charset_type,
+ &encoding_type, &raw_encoded_str);
+ if(ret != DA_RESULT_OK) {
+ goto ERR;
+ }
+
+// DA_SECURE_LOGD("charset = [%s], encoding = [%c], raw = [%s]", charset_type, encoding_type, raw_encoded_str);
+
+ if(encoding_type != 'B') {
+ DA_LOG_ERR(Default, "Encoded Word is not encoded with Base64, but %c. We can only handle Base64.", encoding_type);
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+
+ /*
+ * on glib/gtype.h
+ * typedef char gchar;
+ * typedef unsigned char guchar;
+ *
+ */
+ g_encoded_text = (const gchar*)raw_encoded_str;
+ g_decoded_text = g_base64_decode(g_encoded_text, &g_decoded_text_len);
+
+ if(g_decoded_text) {
+ DA_SECURE_LOGD("g_decoded_text = [%s]", g_decoded_text);
+ decoded_str = (char*)calloc(1, g_decoded_text_len+1);
+ if(!decoded_str) {
+ DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ } else {
+ memcpy(decoded_str, g_decoded_text, g_decoded_text_len);
+ }
+ }
+ DA_SECURE_LOGD("decoded_str = [%s]", decoded_str);
+
+ERR:
+ *out_decoded_ascii_str = decoded_str;
+
+ if(charset_type) {
+ free(charset_type);
+ charset_type = NULL;
+ }
+
+ if(raw_encoded_str) {
+ free(raw_encoded_str);
+ raw_encoded_str = NULL;
+ }
+
+ if(g_decoded_text) {
+ g_free(g_decoded_text);
+ }
+
+ return ret;
+}
+
+
+da_result_t _parsing_base64_encoded_str(const char *in_encoded_str,
+ char **out_charset_type,
+ char *out_encoding_type,
+ char **out_raw_encoded_str)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ const char *org_str = DA_NULL; // e.g. =?UTF-8?B?7Jew7JWE7JmA7IKs7J6QLmpwZw==?=
+ char *charset_type = NULL; // e.g. UTF-8
+ char encoding_type = '\0'; // e.g. B (means Base64)
+ char *raw_encoded_str = NULL; // e.g. 7Jew7JWE7JmA7IKs7J6QLmpwZw==
+
+ char *haystack = DA_NULL;
+ char needle[8] = {0,};
+
+ char *wanted_str = DA_NULL;
+ int wanted_str_len = 0;
+ char *wanted_str_start = DA_NULL;
+ char *wanted_str_end = DA_NULL;
+
+ org_str = in_encoded_str;
+ if (!org_str) {
+ DA_LOG_ERR(Default, "Input string is NULL");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+
+ // strip "=?"
+ haystack = (char*)org_str;
+ snprintf(needle, sizeof(needle), "=?");
+ wanted_str_end = strstr(haystack, needle);
+ if (!wanted_str_end) {
+ DA_LOG_ERR(Default, "DA_ERR_INVALID_ARGUMENT");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ } else {
+ wanted_str = wanted_str_end + strlen(needle);
+ DA_SECURE_LOGD("strip [%s]", wanted_str);
+ }
+
+ // for charset
+ haystack = wanted_str_start = wanted_str;
+ needle[0] = '?';
+ wanted_str_end = strchr(haystack, needle[0]);
+ if (!wanted_str_end) {
+ DA_LOG_ERR(Default, "DA_ERR_INVALID_ARGUMENT");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ } else {
+ wanted_str_len = wanted_str_end - wanted_str_start + 1;
+ wanted_str = (char*)calloc(1, wanted_str_len+1);
+ if (!wanted_str) {
+ DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ } else {
+ snprintf(wanted_str, wanted_str_len+1, "%s", wanted_str_start);
+ charset_type = wanted_str;
+ wanted_str = DA_NULL;
+ }
+
+ DA_LOG(Default, "charset [%s]", charset_type);
+ }
+
+
+ // for encoding
+ encoding_type = *(++wanted_str_end);
+ DA_LOG(Default, "encoding [%c]", encoding_type);
+
+ // for raw encoded str
+ haystack = wanted_str_start = wanted_str_end + 1;
+ snprintf(needle, sizeof(needle), "?=");
+ wanted_str_end = strstr(haystack, needle);
+ if (!wanted_str_end) {
+ DA_LOG_ERR(Default, "DA_ERR_INVALID_ARGUMENT");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ } else {
+ wanted_str_len = wanted_str_end - wanted_str_start + 1;
+ wanted_str = (char*)calloc(1, wanted_str_len+1);
+ if (!wanted_str) {
+ DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ } else {
+ snprintf(wanted_str, wanted_str_len+1, "%s", wanted_str_start);
+ raw_encoded_str = wanted_str;
+ wanted_str = NULL;
+ }
+
+ DA_SECURE_LOGD("raw encoded str [%s]", raw_encoded_str);
+ }
+
+ERR:
+ if (ret != DA_RESULT_OK) {
+ if (charset_type) {
+ free(charset_type);
+ charset_type = NULL;
+ }
+ }
+
+ *out_charset_type = charset_type;
+ *out_encoding_type = encoding_type;
+ *out_raw_encoded_str = raw_encoded_str;
+
+ return ret;
+}
+
+void decode_url_encoded_str(const char *in_encoded_str, char **out_str)
+{
+ char *in = NULL;
+ char *out = NULL;
+ *out_str = calloc(1, strlen(in_encoded_str) + 1);
+ if (*out_str == NULL)
+ return;
+ out = *out_str;
+ in = (char *)in_encoded_str;
+ while (*in)
+ {
+ if (*in == '%') {
+ int hex = 0;
+ in++;
+ if (sscanf(in, "%2x", &hex) <= 0) {
+ return;
+ } else {
+ *out = hex;
+ in++;
+ }
+ } else if (*in == '+') {
+ *out = ' ';
+ } else {
+ *out = *in;
+ }
+ in++;
+ out++;
+ }
+}
+
diff --git a/agent/download-agent-file.c b/agent/download-agent-file.c
new file mode 100755
index 0000000..f871b7c
--- /dev/null
+++ b/agent/download-agent-file.c
@@ -0,0 +1,1138 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <stdio.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <math.h>
+#include <errno.h>
+
+#include "download-agent-client-mgr.h"
+#include "download-agent-debug.h"
+#include "download-agent-utils.h"
+#include "download-agent-dl-mgr.h"
+#include "download-agent-file.h"
+#include "download-agent-mime-util.h"
+#include "download-agent-http-mgr.h"
+#include "download-agent-plugin-conf.h"
+
+#define NO_NAME_TEMP_STR "No name"
+
+static da_result_t __set_file_size(stage_info *stage);
+static da_result_t __saved_file_open(stage_info *stage);
+
+static char *__derive_extension(stage_info *stage);
+static da_result_t __divide_file_name_into_pure_name_N_extesion(
+ const char *in_file_name,
+ char **out_pure_file_name,
+ char **out_extension);
+static da_result_t __get_candidate_file_name(stage_info *stage,
+ char **out_pure_file_name, char **out_extension);
+
+static da_result_t __file_write_buf_make_buf(file_info *file_storage);
+static da_result_t __file_write_buf_destroy_buf(file_info *file_storage);
+static da_result_t __file_write_buf_flush_buf(stage_info *stage,
+ file_info *file_storage);
+static da_result_t __file_write_buf_copy_to_buf(file_info *file_storage,
+ char *body, int body_len);
+static da_result_t __file_write_buf_directly_write(stage_info *stage,
+ file_info *file_storage, char *body, int body_len);
+
+da_result_t clean_files_from_dir(char *dir_path)
+{
+ da_result_t ret = DA_RESULT_OK;
+ struct dirent *d = DA_NULL;
+ DIR *dir;
+ char file_path[DA_MAX_FULL_PATH_LEN] = { 0, };
+
+ DA_LOG_FUNC_LOGD(FileManager);
+
+ if (dir_path == DA_NULL)
+ return DA_ERR_INVALID_ARGUMENT;
+
+ if (is_dir_exist(dir_path)) {
+ dir = opendir(dir_path);
+ if (DA_NULL == dir) {
+ DA_LOG_ERR(FileManager, "opendir() is failed.");
+ ret = DA_ERR_INVALID_INSTALL_PATH;
+ } else {
+ while (DA_NULL != (d = readdir(dir))) {
+ DA_SECURE_LOGD("%s",d->d_name);
+ if (0 == strncmp(d->d_name, ".", strlen("."))
+ || 0 == strncmp(d->d_name,
+ "..",
+ strlen(".."))) {
+ continue;
+ }
+
+ memset(file_path, 0x00, DA_MAX_FULL_PATH_LEN);
+ snprintf(file_path, DA_MAX_FULL_PATH_LEN,
+ "%s/%s", dir_path, d->d_name);
+ if (remove(file_path) < 0) {
+ DA_LOG_ERR(FileManager, "fail to remove file");
+ }
+ }
+
+ closedir(dir);
+ if (remove(dir_path) < 0) {
+ DA_LOG_ERR(FileManager, "fail to remove dir");
+ }
+ }
+ }
+ return ret;
+}
+
+/* Priority to obtain MIME Type
+ * 1. HTTP response header's <Content-Type> field
+ * 2. from OMA descriptor file's <content-type> attribute (mandatory field)
+ * 3. Otherwise, leave blank for MIME Type
+ */
+da_result_t get_mime_type(stage_info *stage, char **out_mime_type)
+{
+ char *mime_type = DA_NULL;
+
+ if (!GET_STAGE_SOURCE_INFO(stage))
+ return DA_ERR_INVALID_ARGUMENT;
+
+ /* Priority 1 */
+ if (GET_REQUEST_HTTP_HDR_CONT_TYPE(GET_STAGE_TRANSACTION_INFO(stage))) {
+ mime_type = GET_REQUEST_HTTP_HDR_CONT_TYPE(GET_STAGE_TRANSACTION_INFO(stage));
+// DA_SECURE_LOGI("content type from HTTP response header [%s]", mime_type);
+ }
+
+ if (!mime_type) {
+ DA_LOG(FileManager, "no content type derived");
+ return DA_RESULT_OK;
+ }
+
+ /* FIXME really need memory allocation? */
+ *out_mime_type = (char *)calloc(1, strlen(mime_type) + 1);
+ if (*out_mime_type) {
+ strncpy(*out_mime_type, mime_type, strlen(mime_type));
+// DA_SECURE_LOGD("out_mime_type str[%s] ptr[%p] len[%d]",
+// *out_mime_type,*out_mime_type,strlen(*out_mime_type));
+ } else {
+ DA_LOG_ERR(FileManager, "fail to allocate memory");
+ return DA_ERR_FAIL_TO_MEMALLOC;
+ }
+
+// DA_SECURE_LOGD("mime type = %s", *out_mime_type);
+ return DA_RESULT_OK;
+}
+
+da_bool_t is_file_exist(const char *file_path)
+{
+ struct stat dir_state;
+ int stat_ret;
+
+ if (file_path == DA_NULL) {
+ DA_LOG_ERR(FileManager, "file path is DA_NULL");
+ return DA_FALSE;
+ }
+
+ stat_ret = stat(file_path, &dir_state);
+
+ if (stat_ret == 0) {
+ if (dir_state.st_mode & S_IFREG) {
+ DA_SECURE_LOGD("Exist! %s is a regular file & its size = %lu", file_path, dir_state.st_size);
+ return DA_TRUE;
+ }
+
+ return DA_FALSE;
+ }
+ return DA_FALSE;
+
+}
+
+da_bool_t is_dir_exist(const char *file_path)
+{
+ struct stat dir_state;
+ int stat_ret;
+
+ if (file_path == DA_NULL) {
+ DA_LOG_ERR(FileManager, "file path is DA_NULL");
+ return DA_FALSE;
+ }
+
+ stat_ret = stat(file_path, &dir_state);
+
+ if (stat_ret == 0) {
+ if (dir_state.st_mode & S_IFDIR) {
+ DA_LOG_VERBOSE(FileManager, "Existed directory.");
+ return DA_TRUE;
+ }
+
+ return DA_FALSE;
+ }
+ return DA_FALSE;
+}
+
+void get_file_size(char *file_path, unsigned long long *out_file_size)
+{
+ struct stat dir_state;
+ int stat_ret;
+
+ *out_file_size = -1;
+
+ if (file_path == DA_NULL) {
+ DA_LOG_ERR(FileManager, "file path is DA_NULL");
+ return;
+ }
+
+ /* Please do not use ftell() to obtain file size, use stat instead.
+ * This is a guide from www.securecoding.cert.org
+ * : FIO19-C. Do not use fseek() and ftell() to compute the size of a file
+ */
+ stat_ret = stat(file_path, &dir_state);
+ if (stat_ret == 0) {
+ if (dir_state.st_mode & S_IFREG) {
+ DA_LOG(FileManager, "size = %lu", dir_state.st_size);
+ *out_file_size = dir_state.st_size;
+ }
+ }
+ return;
+}
+
+da_result_t __saved_file_open(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ file_info *file_storage = DA_NULL;
+ char *actual_file_path = DA_NULL;
+ void *fd = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(FileManager);
+
+ file_storage = GET_STAGE_CONTENT_STORE_INFO(stage);
+ if (!file_storage)
+ return DA_ERR_INVALID_ARGUMENT;
+
+ actual_file_path = GET_CONTENT_STORE_ACTUAL_FILE_NAME(file_storage);
+ if (!actual_file_path)
+ return DA_ERR_INVALID_ARGUMENT;
+
+ fd = fopen(actual_file_path, "a+"); // for resume
+ if (fd == DA_NULL) {
+ DA_LOG_ERR(FileManager, "File open failed");
+ if (errno == ENOSPC)
+ ret = DA_ERR_DISK_FULL;
+ else
+ ret = DA_ERR_FAIL_TO_ACCESS_FILE;
+ goto ERR;
+ }
+ GET_CONTENT_STORE_FILE_HANDLE(file_storage) = fd;
+
+// DA_SECURE_LOGD("file path for saving = %s",
+// GET_CONTENT_STORE_ACTUAL_FILE_NAME(file_storage));
+
+ERR:
+ if (DA_RESULT_OK != ret) {
+ GET_CONTENT_STORE_FILE_HANDLE(file_storage) = DA_NULL;
+ }
+ return ret;
+}
+
+da_result_t __set_file_size(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ req_dl_info *stage_req_info = DA_NULL;
+ file_info *file_storage = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(FileManager);
+
+ if (!stage) {
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+
+ stage_req_info = GET_STAGE_TRANSACTION_INFO(stage);
+
+ file_storage = GET_STAGE_CONTENT_STORE_INFO(stage);
+ if (!file_storage)
+ goto ERR;
+
+ if (GET_REQUEST_HTTP_HDR_CONT_LEN(stage_req_info) != 0) {
+ GET_CONTENT_STORE_FILE_SIZE(file_storage)
+ = GET_REQUEST_HTTP_HDR_CONT_LEN(stage_req_info);
+ } else {
+ GET_CONTENT_STORE_FILE_SIZE(file_storage) = 0;
+ }
+ DA_LOG_VERBOSE(FileManager, "file size = %d", GET_CONTENT_STORE_FILE_SIZE(file_storage));
+ERR:
+ return ret;
+
+}
+
+/* Priority to derive extension
+ * 1. according to MIME-Type
+ * 2. if MIME-Type is ambiguous or blank,
+ * 2-1. derived from <Content-Disposition> field's "filename" attribute
+ * 2-2. derived from url
+ * 3. if url does not have extension, leave blank for extension
+ */
+char *__derive_extension(stage_info *stage)
+{
+ if (!stage)
+ return DA_NULL;
+
+ source_info_t *source_info = GET_STAGE_SOURCE_INFO(stage);
+ req_dl_info *request_info = GET_STAGE_TRANSACTION_INFO(stage);
+ file_info *file_info_data = GET_STAGE_CONTENT_STORE_INFO(stage);
+ char *extension = DA_NULL;
+ char *url = DA_NULL;
+
+ /* Priority 1 */
+ char *mime_type = DA_NULL;
+ mime_type = GET_CONTENT_STORE_CONTENT_TYPE(file_info_data);
+ if (mime_type && !is_ambiguous_MIME_Type(mime_type)) {
+ char *extension = DA_NULL;
+ da_result_t ret = get_extension_from_mime_type(mime_type, &extension);
+ if (ret == DA_RESULT_OK && extension)
+ return extension;
+ }
+
+ /* Priority 2-1 */
+ http_msg_response_t *http_msg_response = DA_NULL;
+ http_msg_response = request_info->http_info.http_msg_response;
+ if (http_msg_response) {
+ char *file_name = DA_NULL;
+ da_bool_t b_ret = http_msg_response_get_content_disposition(http_msg_response,
+ DA_NULL, &file_name);
+ if (b_ret && file_name) {
+ char *extension = DA_NULL;
+ DA_SECURE_LOGD("Name from Content-Disposition :[%s]", file_name);
+ __divide_file_name_into_pure_name_N_extesion(file_name, DA_NULL, &extension);
+ if (file_name) {
+ free(file_name);
+ file_name = DA_NULL;
+ }
+ if (extension)
+ return extension;
+ }
+ }
+ /* Priority 2-2 */
+ /* If there is location url from response header in case of redirection,
+ * it try to parse the extention name from the location url */
+ if (GET_REQUEST_HTTP_REQ_LOCATION(request_info))
+ url = GET_REQUEST_HTTP_REQ_LOCATION(request_info);
+ else
+ url = GET_SOURCE_BASIC_URL(source_info);
+ if (url) {
+ DA_SECURE_LOGD("url:[%s]", url);
+ da_bool_t b_ret = da_get_extension_name_from_url(url, &extension);
+ if (b_ret && extension)
+ return extension;
+ }
+
+ return DA_NULL;
+}
+
+/** Priority for deciding file name
+ * 1. what client wants, which is conveyed by DA_FEATURE_FILE_NAME
+ * 2. 'filename' option on HTTP response header's Content-Disposition field
+ * 3. requesting URL
+ * 4. Otherwise, define it as "No name"
+ */
+da_result_t __get_candidate_file_name(stage_info *stage, char **out_pure_file_name, char **out_extension)
+{
+ da_result_t ret = DA_RESULT_OK;
+ source_info_t *source_info = DA_NULL;
+ char *pure_file_name = DA_NULL;
+ char *extension = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(FileManager);
+
+ if (!stage || !out_pure_file_name)
+ return DA_ERR_INVALID_ARGUMENT;
+
+ source_info = GET_STAGE_SOURCE_INFO(stage);
+ if (!source_info)
+ return DA_ERR_INVALID_ARGUMENT;
+
+ /* Priority 1 */
+ if (!pure_file_name && GET_DL_USER_FILE_NAME(GET_STAGE_DL_ID(stage))) {
+ __divide_file_name_into_pure_name_N_extesion(
+ GET_DL_USER_FILE_NAME(GET_STAGE_DL_ID(stage)),
+ &pure_file_name, &extension);
+ }
+
+ /* Priority 2 */
+ if (!pure_file_name) {
+ req_dl_info *request_info = GET_STAGE_TRANSACTION_INFO(stage);
+ http_msg_response_t *http_msg_response = DA_NULL;
+ http_msg_response = request_info->http_info.http_msg_response;
+ if (http_msg_response) {
+ char *file_name = DA_NULL;
+ da_bool_t b_ret = http_msg_response_get_content_disposition(http_msg_response,
+ DA_NULL, &file_name);
+ if (b_ret && file_name) {
+ DA_SECURE_LOGD("Name from Content-Disposition :[%s]", file_name);
+ __divide_file_name_into_pure_name_N_extesion(file_name, &pure_file_name, &extension);
+ if (file_name) {
+ free(file_name);
+ file_name = DA_NULL;
+ }
+ }
+ }
+ }
+
+ /* Priority 3 */
+ if (!pure_file_name) {
+ char *url = DA_NULL;
+ req_dl_info *request_info = GET_STAGE_TRANSACTION_INFO(stage);
+ /* If there is location url from response header in case of redirection,
+ * it try to parse the file name from the location url */
+ if (GET_REQUEST_HTTP_REQ_LOCATION(request_info))
+ url = GET_REQUEST_HTTP_REQ_LOCATION(request_info);
+ else
+ url = GET_SOURCE_BASIC_URL(source_info);
+ if (url) {
+ DA_SECURE_LOGD("url: [%s]", url);
+ da_get_file_name_from_url(url, &pure_file_name);
+ }
+ }
+
+ /* Priority 4 */
+ if (!pure_file_name) {
+ pure_file_name = strdup(NO_NAME_TEMP_STR);
+ if (!pure_file_name) {
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ }
+ }
+
+ *out_pure_file_name = pure_file_name;
+ pure_file_name = DA_NULL;
+ DA_SECURE_LOGD("candidate file name [%s]", *out_pure_file_name);
+
+ if (out_extension) {
+ if (extension) {
+ *out_extension = extension;
+ extension = DA_NULL;
+ } else {
+ *out_extension = __derive_extension(stage);
+ DA_SECURE_LOGD("candidate extension [%s]", *out_extension);
+ }
+ }
+
+ if (extension)
+ free(extension);
+
+ return DA_RESULT_OK;
+
+ERR:
+ if (extension)
+ free(extension);
+
+ return ret;
+}
+
+da_result_t __decide_file_path(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ char *temp_dir = DA_NULL;
+ char *extension = DA_NULL;
+ char *file_name_without_extension = DA_NULL;
+ char *tmp_file_path = DA_NULL;
+ char *user_install_path = DA_NULL;
+ file_info *file_info_data = DA_NULL;
+ int len = 0;
+ DA_LOG_FUNC_LOGV(FileManager);
+
+ file_info_data = GET_STAGE_CONTENT_STORE_INFO(stage);
+ if (!file_info_data)
+ return DA_ERR_INVALID_ARGUMENT;
+
+
+ /* The destination path is set by user or by CAPI already
+ */
+ user_install_path = GET_DL_USER_INSTALL_PATH(GET_STAGE_DL_ID(stage));
+ len = strlen(user_install_path);
+ temp_dir = (char *)calloc(len + 1, sizeof(char));
+ if (!temp_dir) {
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ }
+ memcpy(temp_dir, user_install_path, len);
+ temp_dir[len] = '\0';
+
+
+
+ ret = __get_candidate_file_name(stage, &file_name_without_extension, &extension);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ // for resume
+ tmp_file_path = get_full_path_avoided_duplication(temp_dir, file_name_without_extension, extension);
+ if (tmp_file_path) {
+ GET_CONTENT_STORE_ACTUAL_FILE_NAME(GET_STAGE_CONTENT_STORE_INFO(stage))
+ = tmp_file_path;
+ tmp_file_path = DA_NULL;
+ } else {
+ ret = DA_ERR_FAIL_TO_ACCESS_FILE;
+ goto ERR;
+ }
+
+ if (file_name_without_extension && !GET_CONTENT_STORE_PURE_FILE_NAME(file_info_data)) {
+ GET_CONTENT_STORE_PURE_FILE_NAME(file_info_data) = file_name_without_extension;
+ file_name_without_extension = DA_NULL;
+ }
+
+ if (extension && !GET_CONTENT_STORE_EXTENSION(file_info_data)) {
+ GET_CONTENT_STORE_EXTENSION(file_info_data) = extension;
+ extension = DA_NULL;
+ }
+
+ERR:
+ DA_SECURE_LOGI("decided file path = %s", GET_CONTENT_STORE_ACTUAL_FILE_NAME(file_info_data));
+ if (temp_dir) {
+ free(temp_dir);
+ temp_dir = DA_NULL;
+ }
+ if (file_name_without_extension) {
+ free(file_name_without_extension);
+ file_name_without_extension = DA_NULL;
+ }
+ if (extension) {
+ free(extension);
+ extension = DA_NULL;
+ }
+ return ret;
+}
+
+char *get_full_path_avoided_duplication(char *in_dir, char *in_candidate_file_name, char *in_extension)
+{
+ char *dir = in_dir;
+ char *file_name = in_candidate_file_name;
+ char *extension = in_extension;
+ char *final_path = DA_NULL;
+
+ int final_path_len = 0;
+ int extension_len = 0;
+
+ int suffix_count = 0; /* means suffix on file name. up to "_1000000000" */
+ const int max_suffix_count = 1000000000;
+ int suffix_len = (int)log10(max_suffix_count+1) + 1; /* 1 means "_" */
+
+ if (!in_dir || !in_candidate_file_name)
+ return DA_NULL;
+
+// DA_SECURE_LOGD("in_candidate_file_name=[%s], in_extension=[%s]", in_candidate_file_name, in_extension);
+
+ if (extension)
+ extension_len = strlen(extension);
+
+ /* first 1 for "/", second 1 for ".", last 1 for DA_NULL */
+ final_path_len = strlen(dir) + 1 + strlen(file_name) + 1
+ + suffix_len + extension_len + 1;
+
+ final_path = (char*)calloc(1, final_path_len);
+ if (!final_path) {
+ DA_LOG_ERR(FileManager, "DA_ERR_FAIL_TO_MEMALLOC");
+ return DA_NULL;
+ }
+
+ do {
+ /* e.g) /tmp/abc.jpg
+ * if there is no extension name, just make a file name without extension */
+ if (0 == extension_len) {
+ if (suffix_count == 0) {
+ snprintf(final_path, final_path_len,
+ "%s/%s", dir, file_name);
+ } else {
+ snprintf(final_path, final_path_len,
+ "%s/%s_%d", dir, file_name, suffix_count);
+ }
+ } else {
+ if (suffix_count == 0) {
+ snprintf(final_path, final_path_len,
+ "%s/%s.%s", dir, file_name, extension);
+ } else {
+ snprintf(final_path, final_path_len,
+ "%s/%s_%d.%s",
+ dir, file_name, suffix_count, extension);
+ }
+ }
+
+ if (is_file_exist(final_path)) {
+ suffix_count++;
+ if (suffix_count > max_suffix_count) {
+ free(final_path);
+ final_path = DA_NULL;
+ break;
+ } else {
+ memset(final_path, 0x00, final_path_len);
+ continue;
+ }
+ }
+
+ break;
+ } while (1);
+
+// DA_SECURE_LOGD("decided path = [%s]", final_path);
+ return final_path;
+}
+
+da_result_t __divide_file_name_into_pure_name_N_extesion(const char *in_file_name, char **out_pure_file_name, char **out_extension)
+{
+ char *file_name = DA_NULL;
+ char *tmp_ptr = DA_NULL;
+ char temp_file[DA_MAX_FILE_PATH_LEN] = {0,};
+ char tmp_ext[DA_MAX_STR_LEN] = {0,};
+ int len = 0;
+ da_result_t ret = DA_RESULT_OK;
+
+ DA_LOG_FUNC_LOGD(FileManager);
+
+ if (!in_file_name)
+ return DA_ERR_INVALID_ARGUMENT;
+
+ file_name = (char *)in_file_name;
+ tmp_ptr = strrchr(file_name, '.');
+ if (tmp_ptr)
+ tmp_ptr++;
+ if (tmp_ptr && out_extension) {
+ strncpy((char*) tmp_ext, tmp_ptr, sizeof(tmp_ext) - 1);
+ *out_extension = strdup((const char*) tmp_ext);
+ DA_SECURE_LOGD("extension [%s]", *out_extension);
+ }
+
+ if (!out_pure_file_name)
+ return ret;
+
+ if (tmp_ptr)
+ len = tmp_ptr - file_name - 1;
+ else
+ len = strlen(file_name);
+
+ if (len >= DA_MAX_FILE_PATH_LEN) {
+ strncpy((char*) temp_file, file_name,
+ DA_MAX_FILE_PATH_LEN - 1);
+ } else {
+ strncpy((char*) temp_file, file_name, len);
+ }
+
+ delete_prohibited_char((char*) temp_file,
+ strlen((char*) temp_file));
+ if (strlen(temp_file) < 1) {
+ *out_pure_file_name = strdup(NO_NAME_TEMP_STR);
+ } else {
+ *out_pure_file_name = strdup(
+ (const char*) temp_file);
+ }
+
+ DA_SECURE_LOGD("pure file name [%s]", *out_pure_file_name);
+ return ret;
+}
+
+da_result_t __file_write_buf_make_buf(file_info *file_storage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ char *buffer = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(FileManager);
+
+ buffer = (char*) calloc(DOWNLOAD_NOTIFY_LIMIT, 1);
+ if (DA_NULL == buffer) {
+ DA_LOG_ERR(FileManager, "Calloc failure ");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ } else {
+ GET_CONTENT_STORE_FILE_BUFF_LEN(file_storage) = 0;
+ GET_CONTENT_STORE_FILE_BUFFER(file_storage) = buffer;
+ }
+
+ return ret;
+}
+
+da_result_t __file_write_buf_destroy_buf(file_info *file_storage)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ DA_LOG_FUNC_LOGV(FileManager);
+
+ if (GET_CONTENT_STORE_FILE_BUFFER(file_storage))
+ free(GET_CONTENT_STORE_FILE_BUFFER(file_storage));
+
+ GET_CONTENT_STORE_FILE_BUFFER(file_storage) = DA_NULL;
+ GET_CONTENT_STORE_FILE_BUFF_LEN(file_storage) = 0;
+
+ return ret;
+}
+
+da_result_t __file_write_buf_flush_buf(stage_info *stage, file_info *file_storage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ char *buffer = DA_NULL;
+ int buffer_size = 0;
+ int write_success_len = 0;
+ void *fd = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(FileManager);
+
+ buffer = GET_CONTENT_STORE_FILE_BUFFER(file_storage);
+ buffer_size = GET_CONTENT_STORE_FILE_BUFF_LEN(file_storage);
+
+ if (buffer_size == 0) {
+ DA_LOG_ERR(FileManager, "no data on buffer..");
+ return ret;
+ }
+
+ fd = GET_CONTENT_STORE_FILE_HANDLE(file_storage);
+ if (DA_NULL == fd) {
+ DA_LOG_ERR(FileManager, "There is no file handle.");
+
+ ret = DA_ERR_FAIL_TO_ACCESS_FILE;
+ goto ERR;
+ }
+ write_success_len = fwrite(buffer, sizeof(char), buffer_size,
+ (FILE *) fd);
+ /* FIXME : This can be necessary later due to progressive download.
+ * The solution for reducing fflush is needed */
+ //fflush((FILE *) fd);
+ if (write_success_len != buffer_size) {
+ DA_LOG_ERR(FileManager, "write fails ");
+ if (errno == ENOSPC)
+ ret = DA_ERR_DISK_FULL;
+ else
+ ret = DA_ERR_FAIL_TO_ACCESS_FILE;
+ goto ERR;
+ }
+ GET_CONTENT_STORE_CURRENT_FILE_SIZE(GET_STAGE_CONTENT_STORE_INFO(stage))
+ += write_success_len;
+ DA_LOG_VERBOSE(FileManager, "write %d bytes", write_success_len);
+ IS_CONTENT_STORE_FILE_BYTES_WRITTEN_TO_FILE(file_storage) = DA_TRUE;
+ GET_CONTENT_STORE_FILE_BUFF_LEN(file_storage) = 0;
+
+ERR:
+ return ret;
+}
+
+da_result_t __file_write_buf_copy_to_buf(file_info *file_storage, char *body,
+ int body_len)
+{
+ da_result_t ret = DA_RESULT_OK;
+ char *buffer = DA_NULL;
+ int buffer_size = 0;
+
+ DA_LOG_FUNC_LOGV(FileManager);
+
+ buffer = GET_CONTENT_STORE_FILE_BUFFER(file_storage);
+ buffer_size = GET_CONTENT_STORE_FILE_BUFF_LEN(file_storage);
+
+ memcpy(buffer + buffer_size, body, body_len);
+ GET_CONTENT_STORE_FILE_BUFF_LEN(file_storage) += body_len;
+
+ return ret;
+}
+
+da_result_t __file_write_buf_directly_write(stage_info *stage,
+ file_info *file_storage, char *body, int body_len)
+{
+ da_result_t ret = DA_RESULT_OK;
+ int write_success_len = 0;
+ void *fd = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(FileManager);
+
+ fd = GET_CONTENT_STORE_FILE_HANDLE(file_storage);
+ if (DA_NULL == fd) {
+ DA_LOG_ERR(FileManager, "There is no file handle.");
+
+ ret = DA_ERR_FAIL_TO_ACCESS_FILE;
+ goto ERR;
+ }
+ write_success_len = fwrite(body, sizeof(char), body_len,
+ (FILE *) fd);
+ /* FIXME : This can be necessary later due to progressive download.
+ * The solution for reducing fflush is needed */
+ //fflush((FILE *) fd);
+ if (write_success_len != body_len) {
+ DA_LOG_ERR(FileManager, "write fails ");
+ if (errno == ENOSPC)
+ ret = DA_ERR_DISK_FULL;
+ else
+ ret = DA_ERR_FAIL_TO_ACCESS_FILE;
+ goto ERR;
+ }
+ GET_CONTENT_STORE_CURRENT_FILE_SIZE(GET_STAGE_CONTENT_STORE_INFO(stage))
+ += write_success_len;
+ DA_LOG(FileManager, "write %d bytes", write_success_len);
+ IS_CONTENT_STORE_FILE_BYTES_WRITTEN_TO_FILE(file_storage) = DA_TRUE;
+
+ERR:
+ return ret;
+}
+
+da_result_t file_write_ongoing(stage_info *stage, char *body, int body_len)
+{
+ da_result_t ret = DA_RESULT_OK;
+ file_info *file_storage = DA_NULL;
+ int buffer_size = 0;
+ char *buffer = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(FileManager);
+
+ file_storage = GET_STAGE_CONTENT_STORE_INFO(stage);
+ if (!file_storage) {
+ DA_LOG_ERR(FileManager, "file_info is empty.");
+ ret = DA_ERR_FAIL_TO_ACCESS_FILE;
+ goto ERR;
+ }
+
+ buffer = GET_CONTENT_STORE_FILE_BUFFER(file_storage);
+ buffer_size = GET_CONTENT_STORE_FILE_BUFF_LEN(file_storage);
+ IS_CONTENT_STORE_FILE_BYTES_WRITTEN_TO_FILE(file_storage) = DA_FALSE;
+
+ if (DA_NULL == buffer) {
+ if (body_len < DOWNLOAD_NOTIFY_LIMIT) {
+ ret = __file_write_buf_make_buf(file_storage);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ __file_write_buf_copy_to_buf(file_storage, body, body_len);
+ } else {
+ ret = __file_write_buf_directly_write(stage,
+ file_storage, body, body_len);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ }
+ } else {
+ if (DOWNLOAD_NOTIFY_LIMIT <= body_len) {
+ ret = __file_write_buf_flush_buf(stage, file_storage);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ ret = __file_write_buf_directly_write(stage,
+ file_storage, body, body_len);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ } else if ((DOWNLOAD_NOTIFY_LIMIT - buffer_size) <= body_len) {
+ ret = __file_write_buf_flush_buf(stage, file_storage);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ __file_write_buf_copy_to_buf(file_storage, body, body_len);
+ } else {
+ __file_write_buf_copy_to_buf(file_storage, body, body_len);
+ }
+ }
+
+ERR:
+ if (ret != DA_RESULT_OK) {
+ if (file_storage) {
+ GET_CONTENT_STORE_FILE_BUFF_LEN(file_storage) = 0;
+ if (GET_CONTENT_STORE_FILE_BUFFER(file_storage)) {
+ free(
+ GET_CONTENT_STORE_FILE_BUFFER(file_storage));
+ GET_CONTENT_STORE_FILE_BUFFER(file_storage)
+ = DA_NULL;
+ }
+ }
+ }
+ return ret;
+}
+
+da_result_t file_write_complete(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ file_info*file_storage = DA_NULL;
+ char *buffer = DA_NULL;
+ unsigned int buffer_size = 0;
+ void *fd = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(FileManager);
+
+ file_storage = GET_STAGE_CONTENT_STORE_INFO(stage);
+ if (!file_storage) {
+ DA_LOG_ERR(FileManager, "file_info is DA_NULL.");
+ ret = DA_ERR_FAIL_TO_ACCESS_FILE;
+ goto ERR;
+ }
+
+ buffer = GET_CONTENT_STORE_FILE_BUFFER(file_storage);
+ buffer_size = GET_CONTENT_STORE_FILE_BUFF_LEN(file_storage);
+
+ if (DA_NULL == buffer) {
+ DA_LOG_ERR(FileManager, "file buffer is DA_NULL");
+ } else {
+ if (buffer_size != 0) {
+ ret = __file_write_buf_flush_buf(stage, file_storage);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ }
+ __file_write_buf_destroy_buf(file_storage);
+ }
+ fd = GET_CONTENT_STORE_FILE_HANDLE(file_storage);
+
+ if (fd) {
+ fclose(fd);
+ fd = DA_NULL;
+ }
+ GET_CONTENT_STORE_FILE_HANDLE(file_storage) = DA_NULL;
+ERR:
+ return ret;
+}
+
+da_result_t start_file_writing(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ file_info *file_info_data = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(FileManager);
+
+ file_info_data = GET_STAGE_CONTENT_STORE_INFO(stage);
+ ret = get_mime_type(stage,
+ &GET_CONTENT_STORE_CONTENT_TYPE(file_info_data));
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ ret = __decide_file_path(stage);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ ret = __set_file_size(stage);
+ if (DA_RESULT_OK != ret)
+ goto ERR;
+
+ GET_CONTENT_STORE_CURRENT_FILE_SIZE(GET_STAGE_CONTENT_STORE_INFO(stage))
+ = 0;
+
+ ret = __saved_file_open(stage);
+
+ERR:
+ return ret;
+}
+
+
+da_result_t start_file_writing_append(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ DA_LOG_FUNC_LOGD(FileManager);
+
+ ret = __saved_file_open(stage);
+
+ return ret;
+}
+
+// for resume with new download request
+da_result_t start_file_writing_append_with_new_download(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ file_info *file_storage = DA_NULL;
+ char *original_file_path = DA_NULL;
+ char *temp_file_path = DA_NULL;
+ char *extension = DA_NULL;
+ char *file_name_without_extension = DA_NULL;
+ req_dl_info *request_info = DA_NULL;
+ unsigned long long temp_file_size = 0;
+
+ DA_LOG_FUNC_LOGD(FileManager);
+
+ file_storage = GET_STAGE_CONTENT_STORE_INFO(stage);
+ if (!file_storage)
+ return DA_ERR_INVALID_ARGUMENT;
+ request_info = GET_STAGE_TRANSACTION_INFO(stage);
+ if (!request_info)
+ return DA_ERR_INVALID_ARGUMENT;
+ temp_file_path = GET_REQUEST_HTTP_USER_REQUEST_TEMP_FILE_PATH(request_info);
+ if (!temp_file_path)
+ return DA_ERR_INVALID_ARGUMENT;
+ original_file_path = GET_CONTENT_STORE_ACTUAL_FILE_NAME(file_storage);
+
+ GET_CONTENT_STORE_ACTUAL_FILE_NAME(file_storage) = strdup(temp_file_path);
+
+ if (original_file_path)
+ free(original_file_path);
+
+ ret = get_mime_type(stage,
+ &GET_CONTENT_STORE_CONTENT_TYPE(file_storage));
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ ret = __get_candidate_file_name(stage, &file_name_without_extension, &extension);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ if (file_name_without_extension) {
+ if (!GET_CONTENT_STORE_PURE_FILE_NAME(file_storage)) {
+ GET_CONTENT_STORE_PURE_FILE_NAME(file_storage) = file_name_without_extension;
+ file_name_without_extension = DA_NULL;
+ } else {
+ free(file_name_without_extension);
+ file_name_without_extension = DA_NULL;
+ }
+ }
+
+ if (extension) {
+ if (!GET_CONTENT_STORE_EXTENSION(file_storage)) {
+ GET_CONTENT_STORE_EXTENSION(file_storage) = extension;
+ extension = DA_NULL;
+ } else {
+ free(extension);
+ extension = DA_NULL;
+ }
+ }
+
+ ret = __set_file_size(stage);
+ if (DA_RESULT_OK != ret)
+ goto ERR;
+ get_file_size(temp_file_path, &temp_file_size);
+ if (temp_file_size < 1)
+ goto ERR;
+
+ GET_CONTENT_STORE_CURRENT_FILE_SIZE(GET_STAGE_CONTENT_STORE_INFO(stage))
+ = temp_file_size;
+
+ ret = __saved_file_open(stage);
+ return ret;
+ERR:
+ if (file_name_without_extension) {
+ free(file_name_without_extension);
+ file_name_without_extension = DA_NULL;
+ }
+
+ if (extension) {
+ free(extension);
+ extension = DA_NULL;
+ }
+ return ret;
+}
+
+da_result_t discard_download(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ file_info *file_storage = DA_NULL;
+ FILE *f_handle = DA_NULL;
+
+ DA_LOG_FUNC_LOGD(FileManager);
+
+ file_storage = GET_STAGE_CONTENT_STORE_INFO(stage);
+
+ f_handle = GET_CONTENT_STORE_FILE_HANDLE(file_storage);
+ if (f_handle) {
+ fclose(f_handle);
+ GET_CONTENT_STORE_FILE_HANDLE(file_storage) = DA_NULL;
+ }
+ return ret;
+}
+
+void clean_paused_file(stage_info *stage)
+{
+ file_info *file_info_data = DA_NULL;
+ char *paused_file_path = DA_NULL;
+ FILE *fd = DA_NULL;
+
+ DA_LOG_FUNC_LOGD(FileManager);
+
+ file_info_data = GET_STAGE_CONTENT_STORE_INFO(stage);
+
+ fd = GET_CONTENT_STORE_FILE_HANDLE(file_info_data);
+ if (fd) {
+ fclose(fd);
+ GET_CONTENT_STORE_FILE_HANDLE(file_info_data) = DA_NULL;
+ }
+
+ paused_file_path = GET_CONTENT_STORE_ACTUAL_FILE_NAME(file_info_data);
+ remove_file((const char*) paused_file_path);
+
+ return;
+}
+
+da_result_t replace_content_file_in_stage(stage_info *stage,
+ const char *dest_dd_file_path)
+{
+ da_result_t ret = DA_RESULT_OK;
+ char *dd_file_path = DA_NULL;
+ int len;
+
+ DA_LOG_FUNC_LOGD(FileManager);
+
+ if (!dest_dd_file_path
+ && (DA_FALSE == is_file_exist(dest_dd_file_path))) {
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+
+ dd_file_path
+ =GET_CONTENT_STORE_ACTUAL_FILE_NAME(GET_STAGE_CONTENT_STORE_INFO(stage));
+
+ if (DA_NULL != dd_file_path) {
+ remove_file((const char*) dd_file_path);
+ free(dd_file_path);
+ }
+ len = strlen(dest_dd_file_path);
+ dd_file_path = calloc(1, len + 1);
+ if (!dd_file_path) {
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ }
+ strncpy(dd_file_path, dest_dd_file_path, len);
+ GET_CONTENT_STORE_ACTUAL_FILE_NAME(GET_STAGE_CONTENT_STORE_INFO(stage))
+ = dd_file_path;
+
+ERR:
+ return ret;
+
+}
+
+da_result_t copy_file(const char *src, const char *dest)
+{
+ FILE *fs = DA_NULL;
+ FILE *fd = DA_NULL;
+ int freadnum = 0;
+ int fwritenum = 0;
+ char buff[4096] = { 0, };
+
+ DA_LOG_FUNC_LOGD(FileManager);
+
+ /* open files to copy */
+ fs = fopen(src, "rb");
+ if (!fs) {
+ DA_LOG_ERR(FileManager, "Fail to open src file");
+ return DA_ERR_FAIL_TO_ACCESS_FILE;
+ }
+
+ fd = fopen(dest, "wb");
+ if (!fd) {
+ DA_LOG_ERR(FileManager, "Fail to open dest file");
+
+ fclose(fs);
+ return DA_ERR_FAIL_TO_ACCESS_FILE;
+ }
+
+ /* actual copy */
+ while (!feof(fs)) {
+ memset(buff, 0x00, 4096);
+ freadnum = fread(buff, sizeof(char), sizeof(buff), fs);
+ if (freadnum > 0) {
+ fwritenum = fwrite(buff, sizeof(char), freadnum, fd);
+ if (fwritenum <= 0) {
+ DA_LOG(FileManager, "written = %d",fwritenum);
+ break;
+ }
+ } else {
+ DA_LOG(FileManager, "read = %d",freadnum);
+ break;
+ }
+ }
+
+ fclose(fd);
+ fclose(fs);
+
+ return DA_RESULT_OK;
+}
+
diff --git a/agent/download-agent-http-mgr.c b/agent/download-agent-http-mgr.c
new file mode 100755
index 0000000..e951308
--- /dev/null
+++ b/agent/download-agent-http-mgr.c
@@ -0,0 +1,1744 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 "download-agent-utils.h"
+#include "download-agent-debug.h"
+#include "download-agent-client-mgr.h"
+#include "download-agent-http-mgr.h"
+#include "download-agent-http-misc.h"
+#include "download-agent-http-msg-handler.h"
+#include "download-agent-file.h"
+#include "download-agent-plugin-conf.h"
+#include "download-agent-plugin-http-interface.h"
+
+da_result_t make_default_http_request_hdr(const char *url,
+ char **user_request_header,
+ int user_request_heaer_count,
+ http_msg_request_t **out_http_msg_request,
+ char *user_request_etag,
+ char *user_request_temp_file_path);
+da_result_t create_resume_http_request_hdr(stage_info *stage,
+ http_msg_request_t **out_resume_request);
+
+da_result_t start_new_transaction(stage_info *stage);
+da_result_t set_http_request_hdr(stage_info *stage);
+da_result_t make_transaction_info_and_start_transaction(stage_info *stage);
+
+da_result_t pause_for_flow_control(stage_info *stage);
+da_result_t unpause_for_flow_control(stage_info *stage);
+
+da_result_t handle_any_input(stage_info *stage);
+da_result_t handle_event_control(stage_info *stage, q_event_t *event);
+da_result_t handle_event_http(stage_info *stage, q_event_t *event);
+da_result_t handle_event_http_packet(stage_info *stage, q_event_t *event);
+da_result_t handle_event_http_final(stage_info *stage, q_event_t *event);
+da_result_t handle_event_http_abort(stage_info *stage, q_event_t *event);
+
+da_result_t exchange_url_from_header_for_redirection(stage_info *stage,
+ http_msg_response_t *http_msg_response);
+
+da_result_t handle_event_abort(stage_info *stage);
+da_result_t handle_event_cancel(stage_info *stage);
+da_result_t handle_event_suspend(stage_info *stage);
+da_result_t handle_event_resume(stage_info *stage);
+da_result_t handle_http_hdr(stage_info *stage,
+ http_msg_response_t *http_msg_response, int http_status);
+da_result_t handle_http_status_code(stage_info *stage,
+ http_msg_response_t *http_msg_response, int http_status);
+da_result_t handle_http_body(stage_info *stage, char *body, int body_len);
+
+da_result_t set_hdr_fields_on_download_info(stage_info *stage);
+
+da_result_t _check_content_type_is_matched(stage_info *stage);
+da_result_t _check_downloaded_file_size_is_same_with_header_content_size(
+ stage_info *stage);
+
+da_result_t _check_resume_download_is_available(stage_info *stage,
+ http_msg_response_t *new_http_msg_response);
+da_result_t _check_this_partial_download_is_available(stage_info *stage,
+ http_msg_response_t *new_http_msg_response);
+
+da_result_t _cancel_transaction(stage_info *stage);
+da_result_t _disconnect_transaction(stage_info *stage);
+
+void __parsing_user_request_header(char *user_request_header,
+ char **out_field, char **out_value);
+
+http_mgr_t http_mgr;
+
+da_result_t init_http_mgr(void)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (http_mgr.is_http_init == DA_FALSE) {
+ http_mgr.is_http_init = DA_TRUE;
+ ret = PI_http_init();
+ }
+
+ return ret;
+}
+
+
+da_result_t request_to_abort_http_download(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ q_event_t *q_event = DA_NULL;
+
+ DA_LOG_FUNC_LOGD(HTTPManager);
+ if (!stage) {
+ DA_LOG_ERR(HTTPManager, "Stage is NULL. download info is already destroyed");
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+
+ DA_LOG(HTTPManager, "Q_EVENT_TYPE_CONTROL_ABORT");
+ ret = Q_make_control_event(Q_EVENT_TYPE_CONTROL_ABORT, &q_event);
+ if (ret != DA_RESULT_OK) {
+ DA_LOG_ERR(HTTPManager, "fail to make q_control_event");
+ goto ERR;
+ } else {
+ DA_LOG(HTTPManager, "queue = %p", GET_DL_QUEUE(GET_STAGE_DL_ID(stage)));
+ Q_push_event(GET_DL_QUEUE(GET_STAGE_DL_ID(stage)), q_event);
+ }
+
+ERR:
+ return ret;
+}
+
+void deinit_http_mgr(void)
+{
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (http_mgr.is_http_init == DA_TRUE) {
+ http_mgr.is_http_init = DA_FALSE;
+ PI_http_deinit();
+ }
+
+ return;
+}
+
+da_result_t request_http_download(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ int slot_id = DA_INVALID_ID;
+ http_state_t http_state = 0;
+ da_bool_t need_wait = DA_TRUE;
+
+ queue_t *queue = DA_NULL;
+ req_dl_info *req_info = DA_NULL;
+
+ slot_id = GET_STAGE_DL_ID(stage);
+ queue = GET_DL_QUEUE(slot_id);
+ req_info = GET_STAGE_TRANSACTION_INFO(stage);
+
+ DA_LOG_VERBOSE(HTTPManager, "queue = %p", GET_DL_QUEUE(slot_id));
+
+ CHANGE_HTTP_STATE(HTTP_STATE_READY_TO_DOWNLOAD, stage);
+
+ do {
+ ret = handle_any_input(stage);
+ if (ret != DA_RESULT_OK) {
+ if (DA_RESULT_OK == GET_REQUEST_HTTP_RESULT(req_info)) {
+ GET_REQUEST_HTTP_RESULT(req_info) = ret;
+ DA_LOG_CRITICAL(HTTPManager, "setting internal error [%d]", ret);
+ }
+ _cancel_transaction(stage);
+ }
+ _da_thread_mutex_lock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+ http_state = GET_HTTP_STATE_ON_STAGE(stage);
+ DA_LOG_VERBOSE(HTTPManager, "http_state = %d", http_state);
+ _da_thread_mutex_unlock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+
+ switch (http_state) {
+ case HTTP_STATE_READY_TO_DOWNLOAD:
+ ret = start_new_transaction(stage);
+ if (ret != DA_RESULT_OK) {
+ if (DA_RESULT_OK == GET_REQUEST_HTTP_RESULT(req_info)) {
+ GET_REQUEST_HTTP_RESULT(req_info) = ret;
+ DA_LOG_CRITICAL(HTTPManager, "setting internal error [%d]", ret);
+ }
+ DA_LOG(HTTPManager, "exiting with error...");
+ need_wait = DA_FALSE;
+ break;
+ }
+
+ CHANGE_HTTP_STATE(HTTP_STATE_DOWNLOAD_REQUESTED, stage);
+ break;
+
+ case HTTP_STATE_CANCELED:
+ case HTTP_STATE_DOWNLOAD_FINISH:
+ case HTTP_STATE_ABORTED:
+#ifdef PAUSE_EXIT
+ case HTTP_STATE_PAUSED:
+#endif
+ DA_LOG_VERBOSE(HTTPManager, "exiting...");
+ need_wait = DA_FALSE;
+ break;
+
+ default:
+ break;
+ }
+
+ if (need_wait == DA_TRUE) {
+ _da_thread_mutex_lock(&(queue->mutex_queue));
+ if (DA_FALSE == GET_IS_Q_HAVING_DATA(queue)) {
+ unpause_for_flow_control(stage);
+
+// DA_LOG_VERBOSE(HTTPManager, "Waiting for input");
+ Q_goto_sleep(queue);
+// DA_LOG_VERBOSE(HTTPManager, "Woke up to receive new packet or control event");
+ }
+ _da_thread_mutex_unlock (&(queue->mutex_queue));
+
+ }
+
+ } while (need_wait == DA_TRUE);
+
+ ret = GET_REQUEST_HTTP_RESULT(req_info);
+ DA_LOG_DEBUG(HTTPManager, "Exit request_http_download! ret[%d]slot_id[%d]",
+ ret, slot_id);
+ return ret;
+}
+
+da_result_t request_to_cancel_http_download(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ q_event_t *q_event = DA_NULL;
+
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ DA_LOG(HTTPManager, "Q_EVENT_TYPE_CONTROL_CANCEL");
+ ret = Q_make_control_event(Q_EVENT_TYPE_CONTROL_CANCEL, &q_event);
+ if (ret != DA_RESULT_OK) {
+ DA_LOG_ERR(HTTPManager, "fail to make q_control_event");
+ goto ERR;
+ } else {
+ DA_LOG(HTTPManager, "queue = %p", GET_DL_QUEUE(GET_STAGE_DL_ID(stage)));
+ Q_push_event(GET_DL_QUEUE(GET_STAGE_DL_ID(stage)), q_event);
+ }
+
+ERR:
+ return ret;
+}
+
+da_result_t request_to_suspend_http_download(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ http_state_t http_state = 0;
+ q_event_t *q_event = DA_NULL;
+
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ _da_thread_mutex_lock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+ http_state = GET_HTTP_STATE_ON_STAGE(stage);
+ DA_LOG(HTTPManager, "http_state = %d", http_state);
+ _da_thread_mutex_unlock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+
+ switch (http_state) {
+ case HTTP_STATE_PAUSED:
+ case HTTP_STATE_REQUEST_PAUSE:
+ DA_LOG_CRITICAL(HTTPManager, "Already paused. http_state = %d", http_state);
+ ret = DA_ERR_ALREADY_SUSPENDED;
+ break;
+
+ default:
+ DA_LOG(HTTPManager, "Q_EVENT_TYPE_CONTROL_SUSPEND");
+ ret = Q_make_control_event(Q_EVENT_TYPE_CONTROL_SUSPEND,
+ &q_event);
+ if (ret != DA_RESULT_OK) {
+ DA_LOG_ERR(HTTPManager, "fail to make q_control_event");
+ goto ERR;
+ } else {
+ DA_LOG(HTTPManager, "queue = %p", GET_DL_QUEUE(GET_STAGE_DL_ID(stage)));
+ Q_push_event(GET_DL_QUEUE(GET_STAGE_DL_ID(stage)),
+ q_event);
+ }
+
+ break;
+ }
+
+ERR:
+ return ret;
+}
+
+da_result_t request_to_resume_http_download(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ http_state_t http_state = 0;
+ q_event_t *q_event = DA_NULL;
+
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ _da_thread_mutex_lock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+ http_state = GET_HTTP_STATE_ON_STAGE(stage);
+ DA_LOG(HTTPManager, "[%d] http_state = %d", GET_STAGE_DL_ID(stage), http_state);
+ _da_thread_mutex_unlock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+
+ switch (http_state) {
+ case HTTP_STATE_PAUSED:
+ DA_LOG(HTTPManager, "Q_EVENT_TYPE_CONTROL_RESUME");
+ ret = Q_make_control_event(Q_EVENT_TYPE_CONTROL_RESUME,
+ &q_event);
+ if (ret != DA_RESULT_OK) {
+ DA_LOG_ERR(HTTPManager, "fail to make q_control_event");
+ goto ERR;
+ } else {
+ DA_LOG(HTTPManager, "queue = %p", GET_DL_QUEUE(GET_STAGE_DL_ID(stage)));
+ Q_push_event(GET_DL_QUEUE(GET_STAGE_DL_ID(stage)),
+ q_event);
+ }
+
+ break;
+
+ case HTTP_STATE_REQUEST_PAUSE:
+ DA_LOG_ERR(HTTPManager, "[%d] Fail to resume. Previous pause is not finished. http_state = %d", GET_STAGE_DL_ID(stage), http_state);
+ ret = DA_ERR_INVALID_STATE;
+
+ break;
+
+ case HTTP_STATE_RESUMED:
+ ret = DA_ERR_ALREADY_RESUMED;
+
+ break;
+
+ default:
+ DA_LOG_ERR(HTTPManager, "[%d] Fail to resume. This is not a paused ID. http_state = %d", GET_STAGE_DL_ID(stage), http_state);
+ ret = DA_ERR_INVALID_STATE;
+
+ break;
+ }
+
+ERR:
+ return ret;
+}
+
+da_result_t start_new_transaction(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ ret = set_http_request_hdr(stage);
+ if (ret != DA_RESULT_OK)
+ return ret;
+
+ ret = make_transaction_info_and_start_transaction(stage);
+ return ret;
+}
+
+da_result_t make_default_http_request_hdr(const char *url,
+ char **user_request_header,
+ int user_request_header_count,
+ http_msg_request_t **out_http_msg_request,
+ char *user_request_etag,
+ char *user_request_temp_file_path)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ http_msg_request_t *http_msg_request = NULL;
+ char *user_agent = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!url) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_NO_URL");
+ ret = DA_ERR_INVALID_URL;
+ goto ERR;
+ }
+
+ ret = http_msg_request_create(&http_msg_request);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ ret = http_msg_request_set_url(http_msg_request, url);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ user_agent = get_user_agent();
+ if (user_agent)
+ http_msg_request_add_field(http_msg_request, HTTP_FIELD_UAGENT,
+ user_agent);
+
+ http_msg_request_add_field(http_msg_request, HTTP_FIELD_ACCEPT_LANGUAGE, "en");
+ http_msg_request_add_field(http_msg_request, HTTP_FIELD_ACCEPT_CHARSET, "utf-8");
+
+ if (user_request_header && user_request_header_count > 0) {
+ int i = 0;
+ for (i = 0; i < user_request_header_count; i++)
+ {
+ char *field = NULL;
+ char *value = NULL;
+ __parsing_user_request_header(user_request_header[i],
+ &field, &value);
+ if (field && value) {
+ http_msg_request_add_field(http_msg_request, field, value);
+ if (field) {
+ free(field);
+ field = NULL;
+ }
+ if (value) {
+ free(value);
+ value= NULL;
+ }
+ } else {
+ if (field) {
+ free(field);
+ field = NULL;
+ }
+ if (value) {
+ free(value);
+ value= NULL;
+ }
+ DA_LOG_ERR(HTTPManager, "Fail to parse user request header");
+ }
+ }
+ } else
+ DA_LOG(HTTPManager, "no user reqeust header inserted");
+
+ if (user_request_etag) {
+ char buff[64] = {0,};
+ unsigned long long size = 0;
+ http_msg_request_add_field(http_msg_request,
+ HTTP_FIELD_IF_RANGE, user_request_etag);
+ get_file_size(user_request_temp_file_path, &size);
+ snprintf(buff, sizeof(buff)-1, "bytes=%llu-", size);
+ http_msg_request_add_field(http_msg_request,
+ HTTP_FIELD_RANGE, buff);
+ }
+
+ *out_http_msg_request = http_msg_request;
+
+ERR:
+ if (ret != DA_RESULT_OK)
+ http_msg_request_destroy(&http_msg_request);
+ if (user_agent)
+ free(user_agent);
+ return ret;
+}
+
+da_result_t set_http_request_hdr(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ req_dl_info *request_info = DA_NULL;
+
+ char *url = DA_NULL;
+ char **user_request_header = DA_NULL;
+ int user_request_header_count = 0;
+ char *user_request_etag = DA_NULL;
+ char *user_request_temp_file_path = DA_NULL;
+ http_msg_request_t* http_msg_request = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ request_info = GET_STAGE_TRANSACTION_INFO(stage);
+
+ if (DA_NULL ==
+ (url = GET_REQUEST_HTTP_REQ_URL(request_info))) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_NO_URL");
+ ret = DA_ERR_INVALID_URL;
+ goto ERR;
+ }
+
+ user_request_header = GET_REQUEST_HTTP_USER_REQUEST_HEADER(
+ request_info);
+ user_request_header_count = GET_REQUEST_HTTP_USER_REQUEST_HEADER_COUNT(
+ request_info);
+ user_request_etag = GET_REQUEST_HTTP_USER_REQUEST_ETAG(
+ request_info);
+ user_request_temp_file_path = GET_REQUEST_HTTP_USER_REQUEST_TEMP_FILE_PATH(
+ request_info);
+ if (user_request_etag) {
+ DA_SECURE_LOGD("user_request_etag[%s]",user_request_etag);
+ } else {
+ DA_LOG_VERBOSE(HTTPManager, "user_request_etag is NULL");
+ }
+ ret = make_default_http_request_hdr(url, user_request_header,
+ user_request_header_count, &http_msg_request,
+ user_request_etag, user_request_temp_file_path);
+ if (ret == DA_RESULT_OK)
+ request_info->http_info.http_msg_request = http_msg_request;
+
+ERR:
+ return ret;
+
+}
+
+da_result_t make_transaction_info_and_start_transaction(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ int slot_id = DA_INVALID_ID;
+ req_dl_info *request_info = DA_NULL;
+
+ input_for_tranx_t *input_for_tranx = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ slot_id = GET_STAGE_DL_ID(stage);
+
+ request_info = GET_STAGE_TRANSACTION_INFO(stage);
+
+ if (GET_REQUEST_HTTP_REQ_URL(request_info) == DA_NULL) {
+ DA_LOG_ERR(HTTPManager, "url is NULL");
+ ret = DA_ERR_INVALID_URL;
+ goto ERR;
+ }
+
+ input_for_tranx = (input_for_tranx_t*) calloc(1,
+ sizeof(input_for_tranx_t));
+ if (input_for_tranx == DA_NULL) {
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ } else {
+ input_for_tranx->proxy_addr = get_proxy_address();
+ input_for_tranx->queue = GET_DL_QUEUE(slot_id);
+
+ input_for_tranx->http_method = PI_HTTP_METHOD_GET;
+ input_for_tranx->http_msg_request
+ = request_info->http_info.http_msg_request;
+ }
+
+ ret = PI_http_start_transaction(input_for_tranx,
+ &(GET_REQUEST_HTTP_TRANS_ID(request_info)));
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ERR:
+ if (input_for_tranx) {
+ free(input_for_tranx);
+ input_for_tranx = DA_NULL;
+ }
+
+ return ret;
+}
+
+da_result_t make_req_dl_info_http(stage_info *stage, req_dl_info *out_info)
+{
+ char *url = DA_NULL;
+ char **user_request_header = DA_NULL;
+ int user_request_header_count = 0;
+ char *user_request_etag = DA_NULL;
+ char *user_request_temp_file_path = DA_NULL;
+ int dl_id = -1;
+ source_info_t *source_info = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!stage) {
+ DA_LOG_ERR(HTTPManager, "stage is NULL");
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+
+ source_info = GET_STAGE_SOURCE_INFO(stage);
+
+ url = source_info->source_info_type.source_info_basic->url;
+ user_request_header =
+ source_info->source_info_type.source_info_basic->user_request_header;
+ user_request_header_count =
+ source_info->source_info_type.source_info_basic->user_request_header_count;
+ dl_id = source_info->source_info_type.source_info_basic->dl_id;
+ user_request_etag = GET_DL_USER_ETAG(GET_STAGE_DL_ID(stage));
+ user_request_temp_file_path = GET_DL_USER_TEMP_FILE_PATH(GET_STAGE_DL_ID(stage));
+
+ DA_SECURE_LOGD("url [%s]", url);
+
+ if (url) {
+ GET_REQUEST_HTTP_REQ_URL(out_info) = url;
+ GET_REQUEST_HTTP_USER_REQUEST_HEADER(out_info) = user_request_header;
+ GET_REQUEST_HTTP_USER_REQUEST_HEADER_COUNT(out_info) =
+ user_request_header_count;
+ GET_REQUEST_HTTP_USER_REQUEST_ETAG(out_info) =
+ user_request_etag;
+ GET_REQUEST_HTTP_USER_REQUEST_TEMP_FILE_PATH(out_info) =
+ user_request_temp_file_path;
+ } else {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_NO_URL");
+ return DA_ERR_INVALID_URL;
+ }
+
+ _da_thread_mutex_init(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)), NULL);
+
+ return DA_RESULT_OK;
+}
+
+da_result_t pause_for_flow_control(stage_info *stage)
+{
+ return DA_RESULT_OK;
+}
+
+da_result_t unpause_for_flow_control(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ PI_http_unpause_transaction(
+ GET_REQUEST_HTTP_TRANS_ID(GET_STAGE_TRANSACTION_INFO(stage)));
+ return ret;
+}
+da_result_t handle_event_abort(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ http_state_t state = 0;
+
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ _da_thread_mutex_lock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+ state = GET_HTTP_STATE_ON_STAGE(stage);
+ DA_LOG(HTTPManager, "http_state = %d", state);
+ _da_thread_mutex_unlock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+ switch (state) {
+ case HTTP_STATE_READY_TO_DOWNLOAD:
+ case HTTP_STATE_REDIRECTED:
+ case HTTP_STATE_DOWNLOAD_REQUESTED:
+ case HTTP_STATE_DOWNLOAD_STARTED:
+ case HTTP_STATE_DOWNLOADING:
+ case HTTP_STATE_REQUEST_CANCEL:
+ case HTTP_STATE_REQUEST_PAUSE:
+ case HTTP_STATE_REQUEST_RESUME:
+ case HTTP_STATE_CANCELED:
+ case HTTP_STATE_PAUSED:
+ case HTTP_STATE_RESUMED:
+ case HTTP_STATE_ABORTED:
+ /* IF the network session is terminated due to some error,
+ * the state can be aborted.(data aborted case) */
+ CHANGE_HTTP_STATE(HTTP_STATE_ABORTED,stage);
+ CHANGE_DOWNLOAD_STATE(DOWNLOAD_STATE_ABORTED, stage);
+ _disconnect_transaction(stage);
+ break;
+ case HTTP_STATE_DOWNLOAD_FINISH:
+ break;
+ default:
+ DA_LOG_ERR(HTTPManager, "have to check the flow for this case");
+ break;
+ }
+ return ret;
+}
+
+da_result_t handle_event_cancel(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ http_state_t state = 0;
+
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ _da_thread_mutex_lock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+ state = GET_HTTP_STATE_ON_STAGE(stage);
+ DA_LOG(HTTPManager, "http_state = %d", state);
+ _da_thread_mutex_unlock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+ switch (state) {
+ case HTTP_STATE_READY_TO_DOWNLOAD:
+ CHANGE_HTTP_STATE(HTTP_STATE_CANCELED,stage);
+ CHANGE_DOWNLOAD_STATE(DOWNLOAD_STATE_CANCELED, stage);
+ break;
+
+ case HTTP_STATE_PAUSED:
+ discard_download(stage);
+ CHANGE_HTTP_STATE(HTTP_STATE_CANCELED,stage);
+ CHANGE_DOWNLOAD_STATE(DOWNLOAD_STATE_CANCELED, stage);
+ break;
+
+ case HTTP_STATE_DOWNLOAD_REQUESTED:
+ case HTTP_STATE_DOWNLOAD_STARTED:
+ case HTTP_STATE_DOWNLOADING:
+ case HTTP_STATE_REQUEST_RESUME:
+ case HTTP_STATE_RESUMED:
+ _cancel_transaction(stage);
+ CHANGE_HTTP_STATE(HTTP_STATE_REQUEST_CANCEL, stage);
+ break;
+
+ case HTTP_STATE_DOWNLOAD_FINISH:
+ break;
+
+ case HTTP_STATE_REQUEST_CANCEL:
+ DA_LOG(HTTPManager, "HTTP_STATE_REQUEST_CANCEL : cancel is already in progress... ");
+ break;
+
+ default:
+ DA_LOG_ERR(HTTPManager, "have to check the flow for this case");
+ break;
+ }
+
+ return ret;
+}
+
+da_result_t handle_event_suspend(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ http_state_t http_state = 0;
+
+ _da_thread_mutex_lock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+ http_state = GET_HTTP_STATE_ON_STAGE(stage);
+ _da_thread_mutex_unlock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+
+ switch (http_state) {
+ case HTTP_STATE_REQUEST_PAUSE:
+ DA_LOG(HTTPManager, "already requested to pause! do nothing");
+ break;
+
+ case HTTP_STATE_READY_TO_DOWNLOAD:
+ CHANGE_HTTP_STATE(HTTP_STATE_PAUSED,stage);
+ CHANGE_DOWNLOAD_STATE(DOWNLOAD_STATE_PAUSED, stage);
+ send_client_paused_info(GET_STAGE_DL_ID(stage));
+ break;
+
+ default:
+ //send_client_paused_info(GET_STAGE_DL_ID(stage));
+ _cancel_transaction(stage);
+ GET_REQUEST_HTTP_RESULT(GET_STAGE_TRANSACTION_INFO(stage)) = DA_RESULT_OK;
+ DA_LOG_CRITICAL(HTTPManager, "[%d] cleanup internal error", GET_STAGE_DL_ID(stage));
+ CHANGE_HTTP_STATE(HTTP_STATE_REQUEST_PAUSE,stage);
+ break;
+ }
+
+ return ret;
+}
+
+da_result_t handle_event_resume(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ http_msg_request_t *resume_request = NULL;
+
+ http_state_t http_state = 0;
+
+ _da_thread_mutex_lock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+ http_state = GET_HTTP_STATE_ON_STAGE(stage);
+ _da_thread_mutex_unlock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+
+ if (http_state != HTTP_STATE_PAUSED) {
+ DA_LOG_ERR(HTTPManager, "Not HTTP_STATE_PAUSED! http_state = %d", http_state);
+ ret = DA_ERR_INVALID_STATE;
+ goto ERR;
+ }
+
+ GET_REQUEST_HTTP_RESULT(GET_STAGE_TRANSACTION_INFO(stage)) = DA_RESULT_OK;
+ DA_LOG_CRITICAL(HTTPManager, "[%d] cleanup internal error", GET_STAGE_DL_ID(stage));
+
+ CHANGE_HTTP_STATE(HTTP_STATE_REQUEST_RESUME,stage);
+ CHANGE_DOWNLOAD_STATE(DOWNLOAD_STATE_NEW_DOWNLOAD,stage);
+
+ ret = create_resume_http_request_hdr(stage, &resume_request);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ if (GET_STAGE_TRANSACTION_INFO(stage)->http_info.http_msg_request)
+ free(GET_STAGE_TRANSACTION_INFO(stage)->http_info.http_msg_request);
+
+ GET_STAGE_TRANSACTION_INFO(stage)->http_info.http_msg_request
+ = resume_request;
+
+ make_transaction_info_and_start_transaction(stage);
+
+ERR:
+ return ret;
+
+}
+
+da_result_t create_resume_http_request_hdr(stage_info *stage,
+ http_msg_request_t **out_resume_request)
+{
+ da_result_t ret = DA_RESULT_OK;
+ da_bool_t b_ret = DA_FALSE;
+
+ req_dl_info *request_info = NULL;
+
+ http_msg_response_t *first_response = NULL;
+ http_msg_request_t *resume_request = NULL;
+
+ char *value = NULL;
+ char *url = NULL;
+ unsigned int downloaded_data_size = 0;
+ char downloaded_data_size_to_str[32] = { 0, };
+
+ char *etag_from_response = NULL;
+ char *date_from_response = NULL;
+
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ request_info = GET_STAGE_TRANSACTION_INFO(stage);
+
+ if (!(url = GET_REQUEST_HTTP_REQ_URL(GET_STAGE_TRANSACTION_INFO(stage)))) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_NO_URL");
+ ret = DA_ERR_INVALID_URL;
+ goto ERR;
+ }
+
+ first_response = request_info->http_info.http_msg_response;
+ if (first_response) {
+ b_ret = http_msg_response_get_ETag(first_response, &value);
+ if (b_ret) {
+ etag_from_response = value;
+ value = NULL;
+ DA_SECURE_LOGD("[ETag][%s]", etag_from_response);
+ }
+
+ b_ret = http_msg_response_get_date(first_response, &value);
+ if (b_ret) {
+ date_from_response = value;
+ value = NULL;
+ DA_SECURE_LOGD("[Date][%s]", date_from_response);
+ }
+
+ downloaded_data_size
+ = GET_CONTENT_STORE_CURRENT_FILE_SIZE(GET_STAGE_CONTENT_STORE_INFO(stage));
+ DA_LOG(HTTPManager, "downloaded_data_size = %u", downloaded_data_size);
+ snprintf(downloaded_data_size_to_str, sizeof(downloaded_data_size_to_str), "bytes=%u-",
+ downloaded_data_size);
+ DA_LOG(HTTPManager, "downloaded_data_size_to_str = %s", downloaded_data_size_to_str);
+ }
+
+ ret = make_default_http_request_hdr(url, NULL, 0, &resume_request, NULL, NULL);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ if (etag_from_response) {
+ http_msg_request_add_field(resume_request, HTTP_FIELD_IF_RANGE,
+ etag_from_response);
+ } else {
+ if (date_from_response) {
+ http_msg_request_add_field(resume_request,
+ HTTP_FIELD_IF_RANGE, date_from_response);
+ }
+ }
+
+ if (strlen(downloaded_data_size_to_str) > 0)
+ http_msg_request_add_field(resume_request, HTTP_FIELD_RANGE,
+ downloaded_data_size_to_str);
+
+ *out_resume_request = resume_request;
+
+ERR:
+ if (etag_from_response) {
+ free(etag_from_response);
+ etag_from_response = NULL;
+ }
+
+ if (date_from_response) {
+ free(date_from_response);
+ date_from_response = NULL;
+ }
+
+ return ret;
+}
+
+da_result_t handle_any_input(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ int slot_id = GET_STAGE_DL_ID(stage);
+
+ queue_t *queue = DA_NULL;
+ q_event_t *event = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ queue = GET_DL_QUEUE(slot_id);
+
+ Q_pop_event(queue, &event);
+ if (event == DA_NULL) {
+ DA_LOG_DEBUG(HTTPManager, "There is no data on the queue!");
+ return DA_RESULT_OK;
+ }
+
+ switch (event->event_type) {
+ case Q_EVENT_TYPE_CONTROL:
+ ret = handle_event_control(stage, event);
+ break;
+
+ case Q_EVENT_TYPE_DATA_HTTP:
+ ret = handle_event_http(stage, event);
+ break;
+
+ case Q_EVENT_TYPE_DATA_DRM:
+ break;
+
+ default:
+ break;
+ }
+ Q_destroy_q_event(&event);
+
+ return ret;
+}
+
+da_result_t handle_event_control(stage_info *stage, q_event_t *event)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ if (event->event_type == Q_EVENT_TYPE_CONTROL) {
+ switch (event->type.q_event_control.control_type) {
+ case Q_EVENT_TYPE_CONTROL_CANCEL:
+ DA_LOG(HTTPManager, "Q_EVENT_TYPE_CONTROL_CANCEL");
+ ret = handle_event_cancel(stage);
+ break;
+
+ case Q_EVENT_TYPE_CONTROL_SUSPEND:
+ DA_LOG(HTTPManager, "Q_EVENT_TYPE_CONTROL_SUSPEND");
+ ret = handle_event_suspend(stage);
+ break;
+
+ case Q_EVENT_TYPE_CONTROL_RESUME:
+ DA_LOG(HTTPManager, "Q_EVENT_TYPE_CONTROL_RESUME");
+ ret = handle_event_resume(stage);
+ break;
+ case Q_EVENT_TYPE_CONTROL_ABORT:
+ DA_LOG(HTTPManager, "Q_EVENT_TYPE_CONTROL_ABORT");
+ ret = handle_event_abort(stage);
+ break;
+ /* Fixme: need to think how we use this type. For now, this type is not used. */
+ case Q_EVENT_TYPE_CONTROL_NET_DISCONNECTED:
+ DA_LOG(HTTPManager, "Q_EVENT_TYPE_CONTROL_NET_DISCONNECTED");
+ break;
+ case Q_EVENT_TYPE_CONTROL_NONE:
+ default:
+ DA_LOG_ERR(HTTPManager, "Cannot enter here");
+ break;
+ }
+ }
+
+ return ret;
+}
+
+da_result_t handle_event_http(stage_info *stage, q_event_t *event)
+{
+ da_result_t ret = DA_RESULT_OK;
+ q_event_data_http_t *q_event_data_http = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (event->event_type == Q_EVENT_TYPE_DATA_HTTP) {
+ q_event_data_http = &(event->type.q_event_data_http);
+ switch (q_event_data_http->data_type) {
+ case Q_EVENT_TYPE_DATA_PACKET:
+ ret = handle_event_http_packet(stage, event);
+ break;
+ case Q_EVENT_TYPE_DATA_FINAL:
+ DA_LOG_VERBOSE(HTTPManager, "Q_EVENT_TYPE_DATA_FINAL");
+ ret = handle_event_http_final(stage, event);
+ break;
+ case Q_EVENT_TYPE_DATA_ABORT:
+ DA_LOG_VERBOSE(HTTPManager, "Q_EVENT_TYPE_DATA_ABORT");
+ ret = handle_event_http_abort(stage, event);
+ break;
+ }
+ }
+ return ret;
+}
+
+da_result_t handle_event_http_packet(stage_info *stage, q_event_t *event)
+{
+ da_result_t ret = DA_RESULT_OK;
+ da_bool_t is_handle_hdr_success = DA_TRUE;
+ q_event_data_http_t *received_data = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ received_data = &(event->type.q_event_data_http);
+
+ if (received_data->http_response_msg) {
+ ret = handle_http_hdr(stage, received_data->http_response_msg,
+ received_data->http_response_msg->status_code);
+ if (DA_RESULT_OK != ret) {
+ is_handle_hdr_success = DA_FALSE;
+ }
+
+ received_data->http_response_msg = NULL;
+ }
+
+ if (received_data->body_len > 0) {
+ if (is_handle_hdr_success == DA_TRUE) {
+ ret = handle_http_body(stage, received_data->body_data,
+ received_data->body_len);
+ }
+ /*For all cases body_data should be deleted*/
+ free(received_data->body_data);
+ received_data->body_data = DA_NULL;
+ }
+ return ret;
+}
+
+da_result_t handle_event_http_final(stage_info *stage, q_event_t *event)
+{
+ da_result_t ret = DA_RESULT_OK;
+ http_state_t http_state = 0;
+ int slot_id = DA_INVALID_ID;
+ int http_status = 0;
+ q_event_data_http_t *received_data = DA_NULL;
+
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ slot_id = GET_STAGE_DL_ID(stage);
+ _disconnect_transaction(stage);
+
+ _da_thread_mutex_lock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+ http_state = GET_HTTP_STATE_ON_STAGE(stage);
+ DA_LOG(HTTPManager, "http_state = %d", http_state);
+ _da_thread_mutex_unlock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+
+ switch (http_state) {
+ case HTTP_STATE_REDIRECTED:
+ CHANGE_HTTP_STATE(HTTP_STATE_READY_TO_DOWNLOAD,stage);
+ break;
+
+ case HTTP_STATE_DOWNLOAD_REQUESTED:
+ DA_LOG(HTTPManager, "case HTTP_STATE_DOWNLOAD_REQUESTED");
+ CHANGE_HTTP_STATE(HTTP_STATE_DOWNLOAD_FINISH, stage);
+ /* Most of http status is decided when got headers.
+ * But it is ignored for credential url when got headers in case of 401 status code.
+ * So, when the download is finished, it means unauthorized error if the status code has still 401.
+ */
+ received_data = &(event->type.q_event_data_http);
+ http_status = received_data->status_code;
+ if (http_status == 401) {
+ store_http_status(slot_id, http_status);
+ ret = DA_ERR_NETWORK_FAIL;
+ }
+ break;
+
+ case HTTP_STATE_DOWNLOADING:
+ DA_LOG_VERBOSE(HTTPManager, "case HTTP_STATE_DOWNLOADING");
+ ret = file_write_complete(stage);
+ if (ret != DA_RESULT_OK) {
+ discard_download(stage);
+ goto ERR;
+ }
+ /* Sometimes, the server can send "0" byte package data although whole data are not sent.
+ * At that case, the libsoup call finished callback function with 200 Ok.
+ * Only if the DA know content size form response header, it can check the error or not
+ */
+ ret = _check_downloaded_file_size_is_same_with_header_content_size(stage);
+ if(ret != DA_RESULT_OK) {
+ discard_download(stage) ;
+ goto ERR;
+ }
+ CHANGE_HTTP_STATE(HTTP_STATE_DOWNLOAD_FINISH, stage);
+ send_client_update_progress_info(
+ slot_id,
+ GET_DL_ID(slot_id),
+ GET_CONTENT_STORE_CURRENT_FILE_SIZE(GET_STAGE_CONTENT_STORE_INFO(stage))
+ );
+ break;
+
+ case HTTP_STATE_REQUEST_PAUSE:
+ if (GET_CONTENT_STORE_FILE_HANDLE(GET_STAGE_CONTENT_STORE_INFO(stage))) {
+ ret = file_write_complete(stage);
+
+ IS_CONTENT_STORE_FILE_BYTES_WRITTEN_TO_FILE(GET_STAGE_CONTENT_STORE_INFO(stage))
+ = DA_FALSE;
+
+ send_client_update_progress_info(
+ slot_id,
+ GET_DL_ID(slot_id),
+ GET_CONTENT_STORE_CURRENT_FILE_SIZE(GET_STAGE_CONTENT_STORE_INFO(stage))
+ );
+
+ }
+ CHANGE_HTTP_STATE(HTTP_STATE_PAUSED,stage);
+ CHANGE_DOWNLOAD_STATE(DOWNLOAD_STATE_PAUSED, stage);
+ send_client_paused_info(GET_STAGE_DL_ID(stage));
+ DA_LOG(HTTPManager, "Server Notification code is set to NULL");
+ break;
+
+ case HTTP_STATE_ABORTED:
+ case HTTP_STATE_CANCELED:
+ discard_download(stage);
+ break;
+
+ case HTTP_STATE_REQUEST_CANCEL:
+ ret = file_write_complete(stage);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ discard_download(stage);
+ CHANGE_HTTP_STATE(HTTP_STATE_CANCELED, stage);
+ CHANGE_DOWNLOAD_STATE(DOWNLOAD_STATE_CANCELED, stage);
+ break;
+
+ default:
+ ret = file_write_complete(stage);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ discard_download(stage);
+ CHANGE_HTTP_STATE(HTTP_STATE_ABORTED,stage);
+ break;
+ }
+
+ERR:
+ /* When file complete is failed */
+ if (DA_RESULT_OK != ret) {
+ CHANGE_HTTP_STATE(HTTP_STATE_DOWNLOAD_FINISH, stage);
+ }
+ return ret;
+}
+
+da_result_t handle_event_http_abort(stage_info *stage, q_event_t *event)
+{
+ da_result_t ret = DA_RESULT_OK;
+ http_state_t http_state = 0;
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ GET_REQUEST_HTTP_RESULT(GET_STAGE_TRANSACTION_INFO(stage))
+ = event->type.q_event_data_http.error_type;
+ DA_LOG_CRITICAL(HTTPManager, "set internal error code : [%d]", GET_REQUEST_HTTP_RESULT(GET_STAGE_TRANSACTION_INFO(stage)));
+ _disconnect_transaction(stage);
+
+ _da_thread_mutex_lock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+ http_state = GET_HTTP_STATE_ON_STAGE(stage);
+ DA_LOG(HTTPManager, "http_state = %d", http_state);
+ _da_thread_mutex_unlock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+
+ switch (http_state) {
+ case HTTP_STATE_REQUEST_PAUSE:
+ CHANGE_HTTP_STATE(HTTP_STATE_PAUSED,stage);
+ CHANGE_DOWNLOAD_STATE(DOWNLOAD_STATE_PAUSED, stage);
+ send_client_paused_info(GET_STAGE_DL_ID(stage));
+ ret = file_write_complete(stage);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ break;
+
+ case HTTP_STATE_REQUEST_CANCEL:
+ CHANGE_HTTP_STATE(HTTP_STATE_CANCELED,stage);
+ CHANGE_DOWNLOAD_STATE(DOWNLOAD_STATE_CANCELED, stage);
+ ret = file_write_complete(stage);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ discard_download(stage);
+ break;
+
+ default:
+ CHANGE_HTTP_STATE(HTTP_STATE_ABORTED,stage);
+ ret = file_write_complete(stage);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ discard_download(stage);
+ break;
+ }
+ERR:
+ return ret;
+}
+
+da_result_t handle_http_hdr(stage_info *stage,
+ http_msg_response_t *http_msg_response, int http_status)
+{
+ da_result_t ret = DA_RESULT_OK;
+ int slot_id = DA_INVALID_ID;
+ http_state_t http_state = 0;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ slot_id = GET_STAGE_DL_ID(stage);
+
+ _da_thread_mutex_lock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+ http_state = GET_HTTP_STATE_ON_STAGE(stage);
+ DA_LOG_DEBUG(HTTPManager, "http_state = %d", http_state);
+ _da_thread_mutex_unlock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+
+ switch (http_state) {
+ case HTTP_STATE_DOWNLOAD_REQUESTED:
+ case HTTP_STATE_REQUEST_PAUSE:
+ case HTTP_STATE_REQUEST_RESUME:
+ case HTTP_STATE_REDIRECTED:
+ ret = handle_http_status_code(stage, http_msg_response,
+ http_status);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ break;
+
+ case HTTP_STATE_REQUEST_CANCEL:
+ DA_LOG(HTTPManager, "Cancel is in progress.. http_state = %d", http_state);
+ break;
+
+ default:
+ DA_LOG_ERR(HTTPManager, "http_state = %d", http_state);
+ goto ERR;
+ }
+
+ERR:
+ return ret;
+}
+
+da_result_t handle_http_status_code(stage_info *stage,
+ http_msg_response_t *http_msg_response, int http_status)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ int slot_id = DA_INVALID_ID;
+ req_dl_info *request_info = DA_NULL;
+ http_state_t http_state = 0;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ slot_id = GET_STAGE_DL_ID(stage);
+ request_info = GET_STAGE_TRANSACTION_INFO(stage);
+
+ GET_STAGE_TRANSACTION_INFO(stage)->http_info.http_msg_response
+ = http_msg_response;
+
+ _da_thread_mutex_lock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+ http_state = GET_HTTP_STATE_ON_STAGE(stage);
+ DA_LOG_VERBOSE(HTTPManager, "http_state = %d", http_state);
+ _da_thread_mutex_unlock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+
+ store_http_status(slot_id, http_status);
+
+ switch (http_status) {
+ case 200:
+ case 201:
+ case 202:
+ case 203:
+ if (http_state == HTTP_STATE_REQUEST_RESUME)
+ clean_paused_file(stage);
+ ret = set_hdr_fields_on_download_info(stage);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ ret = _check_content_type_is_matched(stage);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ CHANGE_HTTP_STATE(HTTP_STATE_DOWNLOAD_STARTED,stage);
+ CHANGE_DOWNLOAD_STATE(DOWNLOAD_STATE_NEW_DOWNLOAD,stage); // ?
+ break;
+
+ case 206:
+ DA_LOG(HTTPManager, "HTTP Status is %d - Partial download for resume!",http_status);
+ /* The resume can be started with start API.
+ * So the state should be not HTTP_STATE_RESUME_REQUESTED but HTTP_STATE_DOWNLOAD_REQUESTED*/
+ if (http_state == HTTP_STATE_DOWNLOAD_REQUESTED) {
+ ret = _check_resume_download_is_available(stage,
+ http_msg_response);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ CHANGE_HTTP_STATE(HTTP_STATE_DOWNLOAD_STARTED,stage);
+
+ } else if (http_state == HTTP_STATE_REQUEST_RESUME) {
+ ret = _check_this_partial_download_is_available(stage,
+ http_msg_response);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ CHANGE_HTTP_STATE(HTTP_STATE_RESUMED,stage);
+ } else {
+ DA_LOG_ERR(HTTPManager, "This download is not resumed, revoke");
+ ret = DA_ERR_INVALID_STATE;
+ goto ERR;
+ }
+ CHANGE_DOWNLOAD_STATE(DOWNLOAD_STATE_NEW_DOWNLOAD,stage);
+ break;
+
+ case 300:
+ case 301:
+ case 302:
+ case 303:
+ case 305:
+ case 306:
+ case 307:
+ DA_LOG(HTTPManager, "HTTP Status is %d - redirection!",http_status);
+ ret = exchange_url_from_header_for_redirection(stage, http_msg_response);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ CHANGE_HTTP_STATE(HTTP_STATE_REDIRECTED,stage);
+ http_msg_response_destroy(&http_msg_response);
+ request_info->http_info.http_msg_response = DA_NULL;
+ break;
+
+ case 100:
+ case 101:
+ case 102:
+ case 204:
+ case 304:
+ DA_LOG(HTTPManager, "HTTP Status is %d - 204 means server got the request, but no content to reply back, 304 means not modified!",http_status);
+ ret = DA_ERR_SERVER_RESPOND_BUT_SEND_NO_CONTENT;
+ break;
+
+ case 416: // Requested range not satisfiable
+ case 503:
+ case 504:
+ default:
+ GET_REQUEST_HTTP_RESULT(request_info)
+ = DA_ERR_UNREACHABLE_SERVER;
+ DA_LOG_CRITICAL(HTTPManager, "set internal error code : DA_ERR_UNREACHABLE_SERVER [%d]", DA_ERR_UNREACHABLE_SERVER);
+ break;
+ }
+
+ERR:
+ return ret;
+}
+
+da_result_t exchange_url_from_header_for_redirection(stage_info *stage,
+ http_msg_response_t *http_msg_response)
+{
+ da_result_t ret = DA_RESULT_OK;
+ char *location = DA_NULL;
+
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ if (http_msg_response_get_location(http_msg_response, &location)) {
+ DA_SECURE_LOGD("location = %s\n", location);
+ GET_REQUEST_HTTP_REQ_LOCATION(GET_STAGE_TRANSACTION_INFO(stage)) = location;
+ }
+
+ return ret;
+}
+
+da_result_t handle_http_body(stage_info *stage, char *body, int body_len)
+{
+ da_result_t ret = DA_RESULT_OK;
+ http_state_t http_state = 0;
+ int slot_id = DA_INVALID_ID;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ slot_id = GET_STAGE_DL_ID(stage);
+
+ if (DA_RESULT_OK
+ != GET_REQUEST_HTTP_RESULT(GET_STAGE_TRANSACTION_INFO(stage))) {
+ DA_LOG_CRITICAL(HTTPManager, "ignore because internal error code is set with [%d]",
+ GET_REQUEST_HTTP_RESULT(GET_STAGE_TRANSACTION_INFO(stage)));
+ return ret;
+ }
+
+ _da_thread_mutex_lock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+ http_state = GET_HTTP_STATE_ON_STAGE(stage);
+ _da_thread_mutex_unlock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+
+ if (http_state == HTTP_STATE_DOWNLOAD_STARTED) {
+ // resume case
+ if (GET_REQUEST_HTTP_USER_REQUEST_ETAG(GET_STAGE_TRANSACTION_INFO(stage)))
+ ret = start_file_writing_append_with_new_download(stage);
+ else
+ ret = start_file_writing(stage);
+ if (DA_RESULT_OK != ret)
+ goto ERR;
+
+ CHANGE_HTTP_STATE(HTTP_STATE_DOWNLOADING, stage);
+ send_client_update_dl_info(
+ slot_id,
+ GET_DL_ID(slot_id),
+ GET_CONTENT_STORE_CONTENT_TYPE(GET_STAGE_CONTENT_STORE_INFO(stage)),
+ GET_CONTENT_STORE_FILE_SIZE(GET_STAGE_CONTENT_STORE_INFO(stage)),
+ GET_CONTENT_STORE_ACTUAL_FILE_NAME(GET_STAGE_CONTENT_STORE_INFO(stage)),
+ GET_CONTENT_STORE_PURE_FILE_NAME(GET_STAGE_CONTENT_STORE_INFO(stage)),
+ GET_REQUEST_HTTP_HDR_ETAG(GET_STAGE_TRANSACTION_INFO(stage)),
+ GET_CONTENT_STORE_EXTENSION(GET_STAGE_CONTENT_STORE_INFO(stage))
+ );
+ } else if (http_state == HTTP_STATE_RESUMED) {
+ ret = start_file_writing_append(stage);
+ if (DA_RESULT_OK != ret)
+ goto ERR;
+
+ CHANGE_HTTP_STATE(HTTP_STATE_DOWNLOADING,stage);
+ send_client_update_dl_info(
+ slot_id,
+ GET_DL_ID(slot_id),
+ GET_CONTENT_STORE_CONTENT_TYPE(GET_STAGE_CONTENT_STORE_INFO(stage)),
+ GET_CONTENT_STORE_FILE_SIZE(GET_STAGE_CONTENT_STORE_INFO(stage)),
+ GET_CONTENT_STORE_ACTUAL_FILE_NAME(GET_STAGE_CONTENT_STORE_INFO(stage)),
+ GET_CONTENT_STORE_PURE_FILE_NAME(GET_STAGE_CONTENT_STORE_INFO(stage)),
+ GET_REQUEST_HTTP_HDR_ETAG(GET_STAGE_TRANSACTION_INFO(stage)),
+ GET_CONTENT_STORE_EXTENSION(GET_STAGE_CONTENT_STORE_INFO(stage))
+ );
+ }
+
+ _da_thread_mutex_lock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+ http_state = GET_HTTP_STATE_ON_STAGE(stage);
+ _da_thread_mutex_unlock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+
+ switch (http_state) {
+ case HTTP_STATE_REDIRECTED:
+ DA_LOG(HTTPManager, "Just ignore http body, because this body is not for redirection one.");
+ break;
+
+ case HTTP_STATE_DOWNLOADING:
+ /* Should this function before updating download info
+ * Because it extract mime type at once only if first download updating at client */
+ ret = file_write_ongoing(stage, body, body_len);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ if ((DA_TRUE ==
+ IS_CONTENT_STORE_FILE_BYTES_WRITTEN_TO_FILE(GET_STAGE_CONTENT_STORE_INFO(stage)))) {
+
+ IS_CONTENT_STORE_FILE_BYTES_WRITTEN_TO_FILE(GET_STAGE_CONTENT_STORE_INFO(stage))
+ = DA_FALSE;
+ send_client_update_progress_info(
+ slot_id,
+ GET_DL_ID(slot_id),
+ GET_CONTENT_STORE_CURRENT_FILE_SIZE(GET_STAGE_CONTENT_STORE_INFO(stage))
+ );
+
+ }
+ break;
+
+ case HTTP_STATE_REQUEST_PAUSE:
+ ret = file_write_ongoing(stage, body, body_len);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ break;
+
+ default:
+ DA_LOG(HTTPManager, "Do nothing! http_state is in case %d", http_state);
+
+ goto ERR;
+ }
+
+ERR:
+ return ret;
+}
+
+/* Function should be renamed , as it is actually not setting the header fields in download info */
+da_result_t set_hdr_fields_on_download_info(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ da_bool_t b_ret = DA_FALSE;
+
+ req_dl_info *request_info = DA_NULL;
+ http_msg_response_t *http_msg_response = NULL;
+
+ char *value = NULL;
+ unsigned long long size = 0;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ request_info = GET_STAGE_TRANSACTION_INFO(stage);
+
+ http_msg_response
+ = request_info->http_info.http_msg_response;
+ if (!http_msg_response) {
+ DA_LOG_ERR(HTTPManager, "There is no header data!!");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+
+ b_ret = http_msg_response_get_content_type(http_msg_response, &value);
+ if (b_ret) {
+ GET_REQUEST_HTTP_HDR_CONT_TYPE(request_info) = value;
+ value = NULL;
+// DA_SECURE_LOGD("[Content-Type][%s] - stored", GET_REQUEST_HTTP_HDR_CONT_TYPE(request_info));
+ }
+
+ b_ret = http_msg_response_get_content_length(http_msg_response,
+ &size);
+ if (b_ret) {
+ GET_REQUEST_HTTP_HDR_CONT_LEN(request_info) = size;
+ size = 0;
+ }
+
+ b_ret = http_msg_response_get_ETag(http_msg_response, &value);
+ if (b_ret) {
+ GET_REQUEST_HTTP_HDR_ETAG(request_info) = value;
+ value = NULL;
+ DA_SECURE_LOGD("[ETag][%s] - stored ", GET_REQUEST_HTTP_HDR_ETAG(request_info));
+ }
+
+ERR:
+ return ret;
+}
+
+da_result_t _check_content_type_is_matched(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ req_dl_info *request_info = DA_NULL;
+ source_info_t *source_info = DA_NULL;
+ char *content_type_from_server = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ request_info = GET_STAGE_TRANSACTION_INFO(stage);
+ source_info = GET_STAGE_SOURCE_INFO(stage);
+
+ content_type_from_server = GET_REQUEST_HTTP_HDR_CONT_TYPE(request_info);
+ if (content_type_from_server == DA_NULL) {
+ DA_LOG(HTTPManager, "http header has no Content-Type field, no need to compare");
+ return DA_RESULT_OK;
+ }
+
+ return ret;
+}
+
+da_result_t _check_this_partial_download_is_available(stage_info *stage,
+ http_msg_response_t *new_http_msg_response)
+{
+ da_result_t ret = DA_RESULT_OK;
+ da_bool_t b_ret = DA_FALSE;
+ char *origin_ETag = NULL;
+ char *new_ETag = NULL;
+ unsigned long long remained_content_len = 0;
+ char *value = NULL;
+ unsigned long long size = 0;
+
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ origin_ETag
+ = GET_REQUEST_HTTP_HDR_ETAG(GET_STAGE_TRANSACTION_INFO(stage));
+
+ b_ret = http_msg_response_get_content_length(new_http_msg_response,
+ &size);
+ if (b_ret) {
+ remained_content_len = size;
+ size = 0;
+ DA_LOG(HTTPManager, "[remained_content_len][%lu]", remained_content_len);
+ }
+
+ b_ret = http_msg_response_get_ETag(new_http_msg_response, &value);
+ if (b_ret) {
+ new_ETag = value;
+ value = NULL;
+ DA_SECURE_LOGD("[new ETag][%s]", new_ETag);
+ } else {
+ goto ERR;
+ }
+
+ if (origin_ETag && new_ETag &&
+ 0 != strncmp(origin_ETag, new_ETag, strlen(new_ETag))) {
+ DA_LOG_ERR(HTTPManager, "ETag is not identical! revoke!");
+ /* FIXME Later : Need to detail error exception handling */
+ ret = DA_ERR_NETWORK_FAIL;
+ /*ret = DA_ERR_MISMATCH_HTTP_HEADER; */
+ goto ERR;
+ }
+
+ERR:
+ if (new_ETag) {
+ free(new_ETag);
+ new_ETag = DA_NULL;
+ }
+
+ return ret;
+}
+
+da_result_t _check_resume_download_is_available(stage_info *stage,
+ http_msg_response_t *new_http_msg_response)
+{
+ da_result_t ret = DA_RESULT_OK;
+ da_bool_t b_ret = DA_FALSE;
+ char *origin_ETag = NULL;
+ char *new_ETag = NULL;
+ unsigned long long remained_content_len = 0;
+ char *value = NULL;
+ unsigned long long size = 0;
+ char *temp_file_path = DA_NULL;
+ req_dl_info *request_info = DA_NULL;
+
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ request_info = GET_STAGE_TRANSACTION_INFO(stage);
+ origin_ETag
+ = GET_REQUEST_HTTP_USER_REQUEST_ETAG(request_info);
+
+ b_ret = http_msg_response_get_content_length(new_http_msg_response,
+ &size);
+ if (b_ret) {
+ remained_content_len = size;
+ size = 0;
+ DA_LOG(HTTPManager, "[remained_content_len][%lu]", remained_content_len);
+ }
+
+ b_ret = http_msg_response_get_ETag(new_http_msg_response, &value);
+ if (b_ret) {
+ new_ETag = value;
+ value = NULL;
+ DA_SECURE_LOGD("[new ETag][%s]", new_ETag);
+ } else {
+ goto ERR;
+ }
+
+ if (origin_ETag && new_ETag &&
+ 0 != strncmp(origin_ETag, new_ETag, strlen(new_ETag))) {
+ DA_LOG_ERR(HTTPManager, "ETag is not identical! revoke!");
+ /* FIXME Later : Need to detail error exception handling */
+ ret = DA_ERR_NETWORK_FAIL;
+ /*ret = DA_ERR_MISMATCH_HTTP_HEADER; */
+ goto ERR;
+ }
+
+ b_ret = http_msg_response_get_content_type(new_http_msg_response, &value);
+ if (b_ret) {
+ GET_REQUEST_HTTP_HDR_CONT_TYPE(request_info) = value;
+ value = NULL;
+ DA_SECURE_LOGD("[Content-Type][%s]",
+ GET_REQUEST_HTTP_HDR_CONT_TYPE(request_info));
+ }
+ temp_file_path = GET_REQUEST_HTTP_USER_REQUEST_TEMP_FILE_PATH(request_info);
+ get_file_size(temp_file_path, &size);
+ GET_REQUEST_HTTP_HDR_CONT_LEN(request_info) = remained_content_len + size;
+ DA_SECURE_LOGD("[Content-Length][%llu]",
+ GET_REQUEST_HTTP_HDR_CONT_LEN(request_info));
+
+
+ERR:
+ if (new_ETag) {
+ free(new_ETag);
+ new_ETag = DA_NULL;
+ }
+
+ return ret;
+}
+
+
+da_result_t _check_downloaded_file_size_is_same_with_header_content_size(
+ stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ req_dl_info *request_info = DA_NULL;
+ file_info *file_info_data = DA_NULL;
+
+ char *real_file_path = DA_NULL;
+ unsigned long long content_size_from_real_file = 0;
+ unsigned long long content_size_from_http_header = 0;
+
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ request_info = GET_STAGE_TRANSACTION_INFO(stage);
+ file_info_data = GET_STAGE_CONTENT_STORE_INFO(stage);
+
+ content_size_from_http_header
+ = GET_CONTENT_STORE_FILE_SIZE(file_info_data);
+
+ if (content_size_from_http_header > 0) {
+ real_file_path
+ = GET_CONTENT_STORE_ACTUAL_FILE_NAME(file_info_data);
+
+ get_file_size(real_file_path,
+ &content_size_from_real_file);
+
+ if (content_size_from_real_file
+ != content_size_from_http_header) {
+ DA_SECURE_LOGE("size from header = %llu, real size = %llu,\
+ DA_ERR_MISMATCH_CONTENT_SIZE",
+ content_size_from_http_header, content_size_from_real_file);
+ ret = DA_ERR_MISMATCH_CONTENT_SIZE;
+ }
+ }
+
+ return ret;
+}
+
+da_result_t _disconnect_transaction(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ int transaction_id = DA_INVALID_ID;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ transaction_id
+ = GET_REQUEST_HTTP_TRANS_ID(GET_STAGE_TRANSACTION_INFO(stage));
+
+ DA_LOG(HTTPManager, "transaction_id = %d slot_id = %d", transaction_id, GET_STAGE_DL_ID(stage));
+
+ if (transaction_id != DA_INVALID_ID) {
+ ret = PI_http_disconnect_transaction(transaction_id);
+ GET_REQUEST_HTTP_TRANS_ID(GET_STAGE_TRANSACTION_INFO(stage))
+ = DA_INVALID_ID;
+ }
+
+ return ret;
+}
+
+da_result_t _cancel_transaction(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ int transaction_id = DA_INVALID_ID;
+
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ transaction_id
+ = GET_REQUEST_HTTP_TRANS_ID(GET_STAGE_TRANSACTION_INFO(stage));
+
+ DA_LOG(HTTPManager, "transaction_id = %d", transaction_id);
+
+ if (transaction_id != DA_INVALID_ID) {
+ http_state_t state = 0;
+ _da_thread_mutex_lock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+ state = GET_HTTP_STATE_ON_STAGE(stage);
+ if (state <= HTTP_STATE_DOWNLOAD_REQUESTED) {
+ _da_thread_mutex_unlock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+ ret = PI_http_cancel_transaction(transaction_id, DA_TRUE);
+ } else {
+ _da_thread_mutex_unlock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(stage)));
+ ret = PI_http_cancel_transaction(transaction_id, DA_FALSE);
+ }
+
+ }
+ return ret;
+}
+
+void __parsing_user_request_header(char *user_request_header,
+ char **out_field, char **out_value)
+{
+ int len = 0;
+ char *pos = NULL;
+ char *temp_pos = NULL;
+ char *field = NULL;
+ char *value = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!user_request_header) {
+ DA_LOG_ERR(HTTPManager, "user_request_header is NULL");
+ goto ERR;
+ }
+
+ pos = strchr(user_request_header, ':');
+ if (!pos) {
+ DA_LOG_ERR(HTTPManager, "Fail to parse");
+ goto ERR;
+ }
+ temp_pos = (char *)user_request_header;
+ while (*temp_pos)
+ {
+ if (temp_pos == pos || *temp_pos == ' ') {
+ len = temp_pos - user_request_header;
+ break;
+ }
+ temp_pos++;
+ }
+ if (len < 1) {
+ DA_LOG_ERR(HTTPManager, "Wrong field name");
+ goto ERR;
+ }
+ field = (char *)calloc(1, len + 1);
+ if (!field) {
+ DA_LOG_ERR(HTTPManager, "Fail to calloc");
+ goto ERR;
+ }
+ strncpy(field, user_request_header, len);
+ pos++;
+ while (*pos)
+ {
+ if (*pos != ' ')
+ break;
+ pos++;
+ }
+ len = strlen(pos) + 1;
+ value = (char *)calloc(1, len + 1);
+ if (!value) {
+ DA_LOG_ERR(HTTPManager, "Fail to calloc");
+ goto ERR;
+ }
+ strncpy(value, pos, len);
+ *out_field = field;
+ *out_value = value;
+ DA_SECURE_LOGD("field[%s], value[%s]", field, value);
+
+ return;
+ERR:
+ if (field) {
+ free(field);
+ field = NULL;
+ }
+ return;
+}
+
diff --git a/agent/download-agent-http-misc.c b/agent/download-agent-http-misc.c
new file mode 100755
index 0000000..08cd8ec
--- /dev/null
+++ b/agent/download-agent-http-misc.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 "download-agent-http-misc.h"
+#include "download-agent-debug.h"
+#include "download-agent-dl-mgr.h"
+#include "download-agent-plugin-conf.h"
+#include "download-agent-client-mgr.h"
+
+#define DEFAULT_HTTP_ACCEPT_HEADERS \
+ "Accept-Language: en\r\n" \
+ "Accept-Charset: utf-8\r\n" \
+
+
+char *get_user_agent()
+{
+ char *uagent_str = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ uagent_str = get_client_user_agent_string();
+ if (!uagent_str) {
+ da_result_t ret = DA_RESULT_OK;
+ ret = get_user_agent_string(&uagent_str);
+ if (ret != DA_RESULT_OK)
+ return NULL;
+ }
+ return uagent_str;
+}
+
+da_bool_t is_supporting_protocol(const char *protocol)
+{
+ if((protocol == NULL) || (1 > strlen(protocol)))
+ {
+ return DA_FALSE;
+ }
+
+ if(!strcasecmp(protocol, "http"))
+ {
+ return DA_TRUE;
+ }
+ else if(!strcasecmp(protocol, "https"))
+ {
+ return DA_TRUE;
+ }
+ else
+ {
+ return DA_FALSE;
+ }
+
+}
diff --git a/agent/download-agent-http-msg-handler.c b/agent/download-agent-http-msg-handler.c
new file mode 100755
index 0000000..6064c37
--- /dev/null
+++ b/agent/download-agent-http-msg-handler.c
@@ -0,0 +1,1333 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "download-agent-http-msg-handler.h"
+#include "download-agent-debug.h"
+#include "download-agent-http-misc.h"
+#include "download-agent-encoding.h"
+
+// '.' and ';' are request from Vodafone
+#define IS_TERMINATING_CHAR(c) ( ((c) == ';') || ((c) == '\0') || ((c) == 0x0d) || ((c) == 0x0a) || ((c) == 0x20) )
+#define IS_TERMINATING_CHAR_EX(c) ( ((c) == '"') || ((c) == ';') || ((c) == '\0') || ((c) == 0x0d) || ((c) == 0x0a) || ((c) == 0x20) )
+#define IS_URI_TERMINATING_CHAR(c) ( ((c) == '\0') || ((c) == 0x0d) || ((c) == 0x0a) || ((c) == 0x20) )
+
+enum parsing_type {
+ WITH_PARSING_OPTION,
+ WITHOUT_PARSING_OPTION
+};
+
+static da_result_t __http_header_add_field(http_header_t **head,
+ const char *field, const char *value, enum parsing_type type);
+static void __http_header_destroy_all_field(http_header_t **head);
+static da_bool_t __get_http_header_for_field(
+ http_msg_response_t *http_msg_response, const char *in_field,
+ http_header_t **out_header);
+static void __exchange_header_value(http_header_t *header,
+ const char *in_raw_value);
+
+static http_header_options_t *__create_http_header_option(const char *field,
+ const char *value);
+static void __http_header_destroy_all_option(http_header_options_t **head);
+static da_bool_t __get_http_header_option_for_field(
+ http_header_options_t *header_option, const char *in_field,
+ char **out_value);
+
+static http_header_options_t *__parsing_N_create_option_str(char *org_str);
+static http_header_options_t *__parsing_options(char *org_str);
+static void __parsing_raw_value(http_header_t *http_header);
+
+da_result_t http_msg_request_create(http_msg_request_t **http_msg_request)
+{
+ http_msg_request_t *temp_http_msg_request = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ temp_http_msg_request = (http_msg_request_t *)calloc(1,
+ sizeof(http_msg_request_t));
+ if (!temp_http_msg_request) {
+ *http_msg_request = NULL;
+ DA_LOG_ERR(HTTPManager, "DA_ERR_FAIL_TO_MEMALLOC");
+ return DA_ERR_FAIL_TO_MEMALLOC;
+ }
+
+ temp_http_msg_request->http_method = NULL;
+ temp_http_msg_request->url = NULL;
+ temp_http_msg_request->head = NULL;
+ temp_http_msg_request->http_body = NULL;
+
+ *http_msg_request = temp_http_msg_request;
+ DA_LOG_DEBUG(HTTPManager, "http_msg_request: %x", (unsigned int)(*http_msg_request));
+
+ return DA_RESULT_OK;
+}
+
+void http_msg_request_destroy(http_msg_request_t **http_msg_request)
+{
+ http_msg_request_t *temp_http_msg_request = *http_msg_request;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (temp_http_msg_request) {
+ if (temp_http_msg_request->http_method) {
+ free(temp_http_msg_request->http_method);
+ temp_http_msg_request->http_method = NULL;
+ }
+
+ if (temp_http_msg_request->url) {
+ free(temp_http_msg_request->url);
+ temp_http_msg_request->url = NULL;
+ }
+
+ if (temp_http_msg_request->http_body) {
+ free(temp_http_msg_request->http_body);
+ temp_http_msg_request->http_body = NULL;
+ }
+
+ __http_header_destroy_all_field(&(temp_http_msg_request->head));
+
+ free(temp_http_msg_request);
+ *http_msg_request = NULL;
+ }
+
+}
+
+da_result_t http_msg_request_set_method(http_msg_request_t *http_msg_request,
+ const char *method)
+{
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ if (!http_msg_request || !method) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_INVALID_ARGUMENT");
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+
+ // ToDo: check method is valid
+
+ http_msg_request->http_method = strdup(method);
+
+ DA_LOG(HTTPManager, "http method : %s", http_msg_request->http_method);
+
+ return DA_RESULT_OK;
+}
+
+da_result_t http_msg_request_get_method(http_msg_request_t *http_msg_request,
+ const char **method)
+{
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!http_msg_request) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_INVALID_ARGUMENT");
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+
+ if (http_msg_request->http_method) {
+ *method = http_msg_request->http_method;
+ return DA_RESULT_OK;
+ } else {
+ *method = DA_NULL;
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+}
+
+da_result_t http_msg_request_set_url(http_msg_request_t *http_msg_request,
+ const char *url)
+{
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!http_msg_request) {
+ DA_LOG_ERR(HTTPManager, "http_msg_request is NULL; DA_ERR_INVALID_ARGUMENT");
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+
+ if (!url) {
+ DA_LOG_ERR(HTTPManager, "url is NULL; DA_ERR_INVALID_ARGUMENT");
+ return DA_ERR_INVALID_URL;
+ }
+
+ http_msg_request->url = strdup(url);
+
+ //DA_SECURE_LOGD("http url : %s", http_msg_request->url);
+
+ return DA_RESULT_OK;
+}
+
+da_result_t http_msg_request_get_url(http_msg_request_t *http_msg_request,
+ const char **url)
+{
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!http_msg_request) {
+ DA_LOG_ERR(HTTPManager, "http_msg_request is NULL; DA_ERR_INVALID_ARGUMENT");
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+
+ if (http_msg_request->url) {
+ *url = http_msg_request->url;
+ return DA_RESULT_OK;
+ } else {
+ *url = DA_NULL;
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+}
+
+da_result_t http_msg_request_set_body(http_msg_request_t *http_msg_request,
+ const char *body)
+{
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!http_msg_request) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_INVALID_ARGUMENT");
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+
+ if (!body)
+ return DA_RESULT_OK;
+
+ http_msg_request->http_body = strdup(body);
+
+ DA_SECURE_LOGD("http body : %s", http_msg_request->http_body);
+
+ return DA_RESULT_OK;
+}
+
+da_result_t http_msg_request_get_body(http_msg_request_t *http_msg_request,
+ const char **body)
+{
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!http_msg_request) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_INVALID_ARGUMENT");
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+
+ if (http_msg_request->http_body) {
+ *body = http_msg_request->http_body;
+ return DA_RESULT_OK;
+ } else {
+ *body = DA_NULL;
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+}
+
+/* FIXME later : check to free filed and value after this API is called */
+da_result_t http_msg_request_add_field(http_msg_request_t *http_msg_request,
+ const char *field, const char *value)
+{
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!http_msg_request) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_INVALID_ARGUMENT");
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+
+ return __http_header_add_field(&(http_msg_request->head), field, value, WITHOUT_PARSING_OPTION);
+}
+
+da_result_t http_msg_response_create(http_msg_response_t **http_msg_response)
+{
+ http_msg_response_t *temp_http_msg_response = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ temp_http_msg_response = (http_msg_response_t *)calloc(1,
+ sizeof(http_msg_response_t));
+ if (!temp_http_msg_response) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_FAIL_TO_MEMALLOC");
+ return DA_ERR_FAIL_TO_MEMALLOC;
+ } else {
+ temp_http_msg_response->status_code = 0;
+ temp_http_msg_response->head = NULL;
+
+ *http_msg_response = temp_http_msg_response;
+
+ return DA_RESULT_OK;
+ }
+}
+
+void http_msg_response_destroy(http_msg_response_t **http_msg_response)
+{
+ http_msg_response_t *temp_http_msg_response = *http_msg_response;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+ if (temp_http_msg_response) {
+ __http_header_destroy_all_field(&(temp_http_msg_response->head));
+
+ free(temp_http_msg_response);
+ *http_msg_response = DA_NULL;
+ }
+}
+
+da_result_t http_msg_response_set_status_code(
+ http_msg_response_t *http_msg_response, int status_code)
+{
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!http_msg_response) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_INVALID_ARGUMENT");
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+
+ http_msg_response->status_code = status_code;
+
+ return DA_RESULT_OK;
+}
+
+da_result_t http_msg_response_get_status_code(
+ http_msg_response_t *http_msg_response, int *status_code)
+{
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ if (!http_msg_response) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_INVALID_ARGUMENT");
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+
+ *status_code = http_msg_response->status_code;
+
+ return DA_RESULT_OK;
+}
+
+da_result_t http_msg_response_add_field(http_msg_response_t *http_msg_response,
+ const char *field, const char *value)
+{
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!http_msg_response) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_INVALID_ARGUMENT");
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+
+ return __http_header_add_field(&(http_msg_response->head), field, value, WITH_PARSING_OPTION);
+}
+
+da_result_t __http_header_add_field(http_header_t **head,
+ const char *field, const char *value, enum parsing_type type)
+{
+ http_header_t *pre = NULL;
+ http_header_t *cur = NULL;
+
+ //DA_SECURE_LOGD("[%s][%s]", field, value);
+
+ pre = cur = *head;
+ while (cur) {
+ pre = cur;
+ /* Replace default value with user wanted value
+ * Remove the value which is stored before and add a new value.
+ */
+ if (cur->field && cur->raw_value &&
+ strncasecmp(cur->field, field, strlen(field)) == 0) {
+ DA_SECURE_LOGD("Remove value for replacement [%s][%s]", cur->field, cur->raw_value);
+ if (cur->field) {
+ free(cur->field);
+ cur->field = NULL;
+ }
+ if (cur->raw_value) {
+ free(cur->raw_value);
+ cur->raw_value= NULL;
+ }
+ }
+ cur = cur->next;
+ }
+
+ cur = (http_header_t *)calloc(1, sizeof(http_header_t));
+ if (cur) {
+ cur->field = strdup(field);
+ cur->raw_value = strdup(value);
+ cur->options = NULL;
+ cur->next = NULL;
+
+ if (type == WITHOUT_PARSING_OPTION) {
+ cur->value = strdup(value);
+ cur->options = NULL;
+ } else {
+ __parsing_raw_value(cur);
+ }
+
+ if (pre)
+ pre->next = cur;
+ else
+ *head = cur;
+ } else {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_FAIL_TO_MEMALLOC");
+ return DA_ERR_FAIL_TO_MEMALLOC;
+ }
+
+ return DA_RESULT_OK;
+}
+
+void __http_header_destroy_all_field(http_header_t **head)
+{
+ http_header_t *pre = NULL;
+ http_header_t *cur = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ cur = *head;
+
+ while (cur) {
+ if (cur->field) {
+ free(cur->field);
+ cur->field = DA_NULL;
+ }
+
+ if (cur->value) {
+ free(cur->value);
+ cur->value = DA_NULL;
+ }
+
+ if (cur->raw_value) {
+ free(cur->raw_value);
+ cur->raw_value = DA_NULL;
+ }
+
+ __http_header_destroy_all_option(&(cur->options));
+
+ pre = cur;
+ cur = cur->next;
+
+ free(pre);
+ }
+
+ *head = DA_NULL;
+}
+
+http_header_options_t *__create_http_header_option(const char *field,
+ const char *value)
+{
+ http_header_options_t *option = NULL;
+
+ option = (http_header_options_t *)calloc(1,
+ sizeof(http_header_options_t));
+ if (option) {
+ if (field)
+ option->field = strdup(field);
+
+ if (value)
+ option->value = strdup(value);
+
+ option->next = NULL;
+ }
+
+ return option;
+}
+
+void __http_header_destroy_all_option(http_header_options_t **head)
+{
+ http_header_options_t *pre = NULL;
+ http_header_options_t *cur = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ cur = *head;
+
+ while (cur) {
+ if (cur->field) {
+ DA_LOG_VERBOSE("field= %s", cur->field);
+ free(cur->field);
+ cur->field = DA_NULL;
+ }
+
+ if (cur->value) {
+ free(cur->value);
+ cur->value = DA_NULL;
+ }
+
+ pre = cur;
+ cur = cur->next;
+
+ free(pre);
+ }
+
+ *head = DA_NULL;
+}
+
+da_result_t http_msg_request_get_iter(http_msg_request_t *http_msg_request,
+ http_msg_iter_t *http_msg_iter)
+{
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!http_msg_request) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_INVALID_ARGUMENT");
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+
+ *http_msg_iter = http_msg_request->head;
+
+ return DA_RESULT_OK;
+}
+
+da_result_t http_msg_response_get_iter(http_msg_response_t *http_msg_response,
+ http_msg_iter_t *http_msg_iter)
+{
+ if (!http_msg_response) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_INVALID_ARGUMENT");
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+
+ *http_msg_iter = http_msg_response->head;
+ // DA_LOG_VERBOSE(HTTPManager, "retrieve iter = 0x%x", (unsigned int)http_msg_iter);
+
+ return DA_RESULT_OK;
+}
+
+da_bool_t http_msg_get_field_with_iter(http_msg_iter_t *http_msg_iter,
+ char **out_field, char **out_value)
+{
+ http_header_t *cur = *http_msg_iter;
+
+ // DA_LOG_VERBOSE(HTTPManager, "getting iter = 0x%x", (unsigned int)cur);
+
+ if (cur) {
+ *out_field = cur->field;
+ *out_value = cur->value;
+ *http_msg_iter = cur->next;
+
+ return DA_TRUE;
+ } else {
+ // DA_LOG_VERBOSE(HTTPManager, "end of iter");
+ return DA_FALSE;
+ }
+}
+
+da_bool_t http_msg_get_header_with_iter(http_msg_iter_t *http_msg_iter,
+ char **out_field, http_header_t **out_header)
+{
+ http_header_t *cur = *http_msg_iter;
+
+ // DA_LOG_VERBOSE(HTTPManager, "getting iter = 0x%x", (unsigned int)cur);
+
+ if (cur) {
+ *out_field = cur->field;
+ *out_header = cur;
+ *http_msg_iter = cur->next;
+
+ return DA_TRUE;
+ } else {
+ // DA_LOG_VERBOSE(HTTPManager, "end of iter");
+ return DA_FALSE;
+ }
+}
+
+http_header_options_t *__parsing_N_create_option_str(char *org_str)
+{
+ char *option_field = NULL;
+ char *option_value = NULL;
+ int option_field_len = 0;
+ int option_value_len = 0;
+
+ char *org_pos = NULL;
+ int org_str_len = 0;
+
+ char *working_str = NULL;
+ char *working_pos = NULL;
+ char *working_pos_field_start = NULL;
+ char *working_pos_value_start = NULL;
+
+ da_bool_t is_inside_quotation = DA_FALSE;
+ da_bool_t is_working_for_field = DA_TRUE;
+ int i = 0;
+ http_header_options_t *option = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!org_str)
+ return NULL;
+
+ org_str_len = strlen(org_str);
+ if (org_str_len <= 0)
+ return NULL;
+
+ working_str = (char *)calloc(1, org_str_len + 1);
+ if (!working_str)
+ return NULL;
+
+ org_pos = org_str;
+ working_pos_field_start = working_pos = working_str;
+
+ for (i = 0; i < org_str_len; i++) {
+ if (*org_pos == '"')
+ is_inside_quotation = !is_inside_quotation;
+
+ if (is_inside_quotation) {
+ // Leave anything including blank if it is inside of double quotation mark.
+ *working_pos = *org_pos;
+ is_working_for_field ? option_field_len++
+ : option_value_len++;
+ working_pos++;
+ org_pos++;
+ } else {
+ if (*org_pos == ' ') {
+ org_pos++;
+ } else if (*org_pos == '=') {
+ if (is_working_for_field) {
+ is_working_for_field = DA_FALSE;
+ working_pos_value_start = working_pos;
+ }
+
+ org_pos++;
+ } else {
+ *working_pos = *org_pos;
+ is_working_for_field ? option_field_len++
+ : option_value_len++;
+ working_pos++;
+ org_pos++;
+ }
+ }
+ }
+
+ if (option_field_len > 0 && working_pos_field_start) {
+ option_field = (char *)calloc(1, option_field_len + 1);
+ if (option_field)
+ strncpy(option_field, working_pos_field_start,
+ option_field_len);
+ }
+
+ if (option_value_len > 0 && working_pos_value_start) {
+ option_value = (char *)calloc(1, option_value_len + 1);
+ if (option_value)
+ strncpy(option_value, working_pos_value_start,
+ option_value_len);
+ }
+
+ if (working_str) {
+ free(working_str);
+ working_pos = working_str = NULL;
+ }
+
+// DA_SECURE_LOGD("option_field = [%s], option_value = [%s]",
+// option_field, option_value);
+
+ if (option_field || option_value) {
+ option = __create_http_header_option(
+ option_field, option_value);
+ if (option_field) {
+ free(option_field);
+ option_field = NULL;
+ }
+
+ if (option_value) {
+ free(option_value);
+ option_value = NULL;
+ }
+ }
+ return option;
+}
+
+http_header_options_t *__parsing_options(char *org_str)
+{
+ da_result_t ret = DA_RESULT_OK;
+ http_header_options_t *head = NULL;
+ http_header_options_t *pre = NULL;
+ http_header_options_t *cur = NULL;
+
+ int wanted_str_len = 0;
+ char *wanted_str = NULL;
+ char *wanted_str_start = NULL;
+ char *wanted_str_end = NULL;
+ char *cur_pos = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!org_str)
+ return NULL;
+
+ /* Do Not use strtok(). It's not thread safe. */
+ // DA_SECURE_LOGD("org_str = %s", org_str);
+
+ cur_pos = org_str;
+
+ while (cur_pos) {
+ wanted_str_start = cur_pos;
+ wanted_str_end = strchr(cur_pos, ';');
+ if (wanted_str_end) {
+ cur_pos = wanted_str_end + 1;
+ } else {
+ wanted_str_end = org_str + strlen(org_str);
+ cur_pos = NULL;
+ }
+
+ wanted_str_len = wanted_str_end - wanted_str_start;
+ wanted_str = (char *)calloc(1, wanted_str_len + 1);
+ if (!wanted_str) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_FAIL_TO_MEMALLOC");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ }
+ strncpy(wanted_str, wanted_str_start, wanted_str_len);
+
+ // DA_SECURE_LOGD("wanted_str = [%s]", wanted_str);
+ cur = __parsing_N_create_option_str(wanted_str);
+ if (pre) {
+ pre->next = cur;
+ pre = cur;
+ } else {
+ head = pre = cur;
+ }
+
+ free(wanted_str);
+ wanted_str = NULL;
+ }
+
+ERR:
+ if (ret != DA_RESULT_OK)
+ __http_header_destroy_all_option(&head);
+
+ return head;
+}
+
+void __parsing_raw_value(http_header_t *http_header_field)
+{
+ char *raw_value = NULL;
+ char *option_str_start = NULL;
+
+ char *trimed_value = NULL;
+ int trimed_value_len = 0;
+
+ char *trimed_value_start = NULL;
+ char *trimed_value_end = NULL;
+
+ raw_value = http_header_field->raw_value;
+ // DA_SECURE_LOGD("raw_value = [%s]", raw_value);
+
+ if (!raw_value)
+ return;
+
+ trimed_value_start = raw_value;
+
+ trimed_value_end = strchr(raw_value, ';');
+ if (!trimed_value_end) {
+ // No options
+ http_header_field->value = strdup(raw_value);
+ http_header_field->options = NULL;
+
+ return;
+ }
+
+ // for trimed value
+ trimed_value_len = trimed_value_end - trimed_value_start;
+
+ trimed_value = (char *)calloc(1, trimed_value_len + 1);
+ if (!trimed_value) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_FAIL_TO_MEMALLOC");
+ return;
+ }
+ strncpy(trimed_value, trimed_value_start, trimed_value_len);
+ http_header_field->value = trimed_value;
+
+ // for option parsing
+ option_str_start = trimed_value_end + 1;
+
+ http_header_field->options = __parsing_options(option_str_start);
+
+ /////////////// show
+ http_header_options_t *cur = NULL;
+
+ cur = http_header_field->options;
+ while (cur) {
+// DA_SECURE_LOGD("field = [%s], value = [%s]", cur->field, cur->value);
+ cur = cur->next;
+ }
+
+}
+
+da_bool_t __get_http_header_option_for_field(
+ http_header_options_t *header_option, const char *in_field,
+ char **out_value)
+{
+ http_header_options_t *cur = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!header_option) {
+ DA_LOG_ERR(HTTPManager, "input header_option is NULL.");
+ return DA_FALSE;
+ }
+
+ cur = header_option;
+ while (cur) {
+ if (cur->field) {
+ if (!strncasecmp(cur->field, in_field, strlen(cur->field)) &&
+ cur->value) {
+ DA_SECURE_LOGD("[%s][%s]", cur->field, cur->value);
+ *out_value = cur->value;
+ return DA_TRUE;
+ }
+
+ }
+ cur = cur->next;
+ }
+
+ return DA_FALSE;
+}
+
+da_bool_t __get_http_header_for_field(http_msg_response_t *http_msg_response,
+ const char *in_field, http_header_t **out_header)
+{
+ http_msg_iter_t http_msg_iter;
+ http_header_t *header = NULL;
+ char *field = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ http_msg_response_get_iter(http_msg_response, &http_msg_iter);
+ while (http_msg_get_header_with_iter(&http_msg_iter, &field, &header)) {
+ if (field && header && !strncasecmp(field, in_field, strlen(field))) {
+// DA_SECURE_LOGD("[%s][%s]", field, header->value);
+ *out_header = header;
+ return DA_TRUE;
+ }
+ }
+
+ return DA_FALSE;
+}
+
+void __exchange_header_value(http_header_t *header, const char *in_raw_value)
+{
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!header || !in_raw_value)
+ return;
+
+ __http_header_destroy_all_option(&(header->options));
+
+ if (header->value) {
+ free(header->value);
+ header->value = DA_NULL;
+ }
+
+ if (header->raw_value)
+ free(header->raw_value);
+ header->raw_value = strdup(in_raw_value);
+
+ __parsing_raw_value(header);
+}
+
+da_bool_t http_msg_response_get_content_type(
+ http_msg_response_t *http_msg_response, char **out_type)
+{
+ da_bool_t b_ret = DA_FALSE;
+ http_header_t *header = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ b_ret = __get_http_header_for_field(http_msg_response, "Content-Type",
+ &header);
+ if (!b_ret) {
+ DA_LOG(HTTPManager, "no Content-Type");
+ return DA_FALSE;
+ }
+
+ if (out_type)
+ *out_type = strdup(header->value);
+
+ return DA_TRUE;
+}
+
+void http_msg_response_set_content_type(http_msg_response_t *http_msg_response,
+ const char *in_type)
+{
+ da_bool_t b_ret = DA_FALSE;
+ http_header_t *header = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!http_msg_response || !in_type)
+ return;
+
+ b_ret = __get_http_header_for_field(http_msg_response, "Content-Type",
+ &header);
+ if (b_ret) {
+ if (header->raw_value && (!strncmp(header->raw_value, in_type,
+ strlen(header->raw_value))))
+ return;
+
+ DA_SECURE_LOGD("exchange Content-Type to [%s] from [%s]", in_type, header->value);
+ __exchange_header_value(header, in_type);
+ } else {
+ __http_header_add_field(&(http_msg_response->head),
+ "Content-Type", in_type, WITH_PARSING_OPTION);
+ }
+}
+
+da_bool_t http_msg_response_get_content_length(
+ http_msg_response_t *http_msg_response, unsigned long long *out_length)
+{
+ da_bool_t b_ret = DA_FALSE;
+ http_header_t *header = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ b_ret = __get_http_header_for_field(http_msg_response,
+ "Content-Length", &header);
+ if (!b_ret) {
+ DA_LOG(HTTPManager, "no Content-Length");
+ return DA_FALSE;
+ }
+
+ if (out_length)
+ *out_length = atoll(header->value);
+
+ return DA_TRUE;
+}
+
+da_bool_t http_msg_response_get_content_disposition(
+ http_msg_response_t *http_msg_response, char **out_disposition,
+ char **out_file_name)
+{
+ da_bool_t b_ret = DA_FALSE;
+ http_header_t *header = NULL;
+ char *file_name = NULL;
+
+ char *wanted_str = NULL;
+ char *wanted_str_start = NULL;
+ char *wanted_str_end = NULL;
+ char *decoded_str = NULL;
+ int wanted_str_len = 0;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ b_ret = __get_http_header_for_field(http_msg_response,
+ "Content-Disposition", &header);
+ if (!b_ret) {
+ DA_LOG_VERBOSE(HTTPManager, "no Content-Disposition");
+ return DA_FALSE;
+ }
+
+ if (out_disposition)
+ *out_disposition = strdup(header->value);
+
+ if (!out_file_name)
+ return DA_FALSE;
+
+ b_ret = __get_http_header_option_for_field(header->options, "filename",
+ &file_name);
+ if (!b_ret) {
+ DA_LOG(HTTPManager, "no option");
+ return DA_FALSE;
+ }
+
+ // eliminate double quotation mark if it exists on derived value
+ wanted_str_start = strchr(file_name, '"');
+ if (!wanted_str_start) {
+ *out_file_name = strdup(file_name);
+ return DA_TRUE;
+ } else {
+ // DA_SECURE_LOGD("wanted_str_start = [%s]", wanted_str_start);
+ wanted_str_start++;
+ wanted_str_end = strchr(wanted_str_start, '"');
+ if (wanted_str_end) {
+ wanted_str_len = wanted_str_end - wanted_str_start;
+ wanted_str = (char*)calloc(1, wanted_str_len + 1);
+ if (!wanted_str) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_FAIL_TO_MEMALLOC");
+ return DA_FALSE;
+ }
+ strncpy(wanted_str, wanted_str_start, wanted_str_len);
+
+ b_ret = is_base64_encoded_word(wanted_str);
+ if (b_ret) {
+ DA_LOG(HTTPManager, "It's base64 encoded-word string");
+ if (DA_RESULT_OK == decode_base64_encoded_str(
+ wanted_str, &decoded_str)) {
+ DA_SECURE_LOGD("base64 decoded str = [%s]", decoded_str);
+ free(wanted_str);
+ wanted_str = decoded_str;
+ decoded_str = NULL;
+ } else {
+ DA_LOG(HTTPManager, "Fail to base64 decode. Just use un-decoded string.");
+ }
+ } else {
+ DA_LOG(HTTPManager, "It's NOT base64 encoded-word string");
+ }
+ decode_url_encoded_str(wanted_str, &decoded_str);
+ /* If it is url encoded string */
+ if (decoded_str) {
+ DA_SECURE_LOGD("Url decoded str = [%s]", decoded_str);
+ free(wanted_str);
+ wanted_str = decoded_str;
+ decoded_str = NULL;
+ }
+
+ *out_file_name = wanted_str;
+
+ DA_SECURE_LOGD("out_file_name = [%s]", *out_file_name);
+
+ return DA_TRUE;
+ } else {
+ DA_LOG_ERR(HTTPManager, "Not matched \" !");
+ return DA_FALSE;
+ }
+ }
+}
+
+da_bool_t http_msg_response_get_ETag(http_msg_response_t *http_msg_response,
+ char **out_value)
+{
+ da_bool_t b_ret = DA_FALSE;
+ http_header_t *header = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ b_ret = __get_http_header_for_field(http_msg_response, "ETag", &header);
+ if (!b_ret) {
+ DA_LOG_VERBOSE(HTTPManager, "no ETag");
+ return DA_FALSE;
+ }
+
+ if (out_value)
+ *out_value = strdup(header->value);
+
+ return DA_TRUE;
+}
+
+da_bool_t http_msg_response_get_date(http_msg_response_t *http_msg_response,
+ char **out_value)
+{
+ da_bool_t b_ret = DA_FALSE;
+ http_header_t *header = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ b_ret = __get_http_header_for_field(http_msg_response, "Date", &header);
+ if (!b_ret) {
+ DA_LOG(HTTPManager, "no Date");
+ return DA_FALSE;
+ }
+
+ if (out_value)
+ *out_value = strdup(header->value);
+
+ return DA_TRUE;
+}
+
+da_bool_t http_msg_response_get_location(http_msg_response_t *http_msg_response,
+ char **out_value)
+{
+ da_bool_t b_ret = DA_FALSE;
+ http_header_t *header = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ b_ret = __get_http_header_for_field(http_msg_response, "Location", &header);
+ if (!b_ret) {
+ DA_LOG(HTTPManager, "no Location");
+ return DA_FALSE;
+ }
+ if (out_value)
+ *out_value = strdup(header->value);
+
+ return DA_TRUE;
+}
+
+da_result_t http_msg_response_get_boundary(
+ http_msg_response_t *http_msg_response, char **out_val)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ http_msg_iter_t http_msg_iter;
+ char *field = NULL;
+ char *value = NULL;
+ char *boundary = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!http_msg_response) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_INVALID_ARGUMENT");
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+
+ http_msg_response_get_iter(http_msg_response, &http_msg_iter);
+ while (http_msg_get_field_with_iter(&http_msg_iter, &field, &value)) {
+ if ((field != DA_NULL) && (value != DA_NULL)) {
+ if (!strncasecmp(field, "Content-Type",
+ strlen("Content-Type"))) {
+ char *org_str = NULL;
+ char *boundary_str_start = NULL;
+ char *boundary_value_start = NULL;
+ char *boundary_value_end = NULL;
+ int boundary_value_len = 0;
+
+ org_str = value;
+
+ boundary_str_start
+ = strstr(org_str, "boundary");
+ if (boundary_str_start) {
+ DA_LOG(HTTPManager, "boundary_str_start = %s", boundary_str_start);
+ // this "Content-Type" value has "boundary" in it, so get the value
+ boundary_value_start = strchr(
+ boundary_str_start, '"');
+ boundary_value_start += 1; // start without "
+
+ boundary_value_end = strchr(
+ boundary_value_start, '"');
+ boundary_value_len = boundary_value_end
+ - boundary_value_start;
+
+ DA_LOG(HTTPManager, "boundary_value_start = %s", boundary_value_start);
+ DA_LOG(HTTPManager, "boundary_value_end = %s", boundary_value_end);
+ DA_LOG(HTTPManager, "boundary_value_len = %d", boundary_value_len);
+
+ } else {
+ // no "boundary" field on this "Content-Type" value
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+ // end of clear
+
+ boundary = (char *)calloc(1,
+ boundary_value_len + 1);
+ if (!boundary) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_FAIL_TO_MEMALLOC");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+
+ goto ERR;
+ }
+ strncpy(boundary, boundary_value_start,
+ boundary_value_len);
+ DA_SECURE_LOGD("[boundary][%s]", boundary);
+ break;
+ }
+ }
+ }
+
+ *out_val = boundary;
+
+ERR:
+ return ret;
+}
+
+char *get_http_response_header_raw(http_msg_response_t *http_msg_response)
+{
+ http_msg_iter_t http_msg_iter;
+ http_header_t *header = NULL;
+ char *field = NULL;
+ char tmp_buf[1024*4] = {0,};
+ char line_buf[1024] = {0,};
+ int len = 0;
+ char *buff = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ http_msg_response_get_iter(http_msg_response, &http_msg_iter);
+ while (http_msg_get_header_with_iter(&http_msg_iter, &field, &header)) {
+ if (field && header) {
+ // FIXME later :: buffer length is more than total length. think about getting header's conent length from libsoup
+ len = strlen(field) + strlen(header->value) + 2;
+ snprintf(line_buf, len,"%s:%s", field, header->value);
+ strncat(tmp_buf, line_buf, len);
+ strcat(tmp_buf, "\n");
+ }
+ }
+ if (strlen(tmp_buf) > 0) {
+ buff = (char *)calloc(1, strlen(tmp_buf) + 1);
+ if (buff == DA_NULL) {
+ DA_LOG_ERR(HTTPManager, "DA_ERR_FAIL_TO_MEMALLOC");
+ return DA_NULL;
+ }
+ memcpy(buff, tmp_buf, strlen(tmp_buf));
+ DA_SECURE_LOGD("\n---raw response header---\n%s\n------\n",buff);
+ return buff;
+ } else {
+ return DA_NULL;
+ }
+}
+
+char *_stristr(const char *long_str, const char *find_str)
+{
+ int i = 0;
+ int length_long = 0;
+ int length_find = 0;
+ char *ret_ptr = NULL;
+ char *org_ptr = NULL;
+ char *look_ptr = NULL;
+
+ if (long_str == NULL || find_str == NULL) {
+ DA_LOG_ERR(Default,"INVALID ARGUMENT");
+ return NULL;
+ }
+
+ length_long = strlen(long_str);
+ length_find = strlen(find_str);
+
+ org_ptr = (char*)calloc(1, length_long + 1);
+
+ if (org_ptr == NULL) {
+ DA_LOG_ERR(Default,"INVALID ARGUMENT");
+ return NULL;
+ }
+
+ look_ptr = (char*)calloc(1, length_find + 1);
+
+ if (look_ptr == NULL) {
+ DA_LOG_ERR(Default,"INVALID ARGUMENT");
+ free(org_ptr);
+ return NULL;
+ }
+
+ while (i < length_long) {
+ if (isalpha(long_str[i]) != 0) {
+ if (isupper(long_str[i]) != 0) {
+ org_ptr[i] = long_str[i];
+ } else {
+ org_ptr[i] = toupper(long_str[i]);
+ }
+ } else {
+ org_ptr[i] = long_str[i];
+ }
+
+ i++;
+ }
+
+ i = 0;
+
+ while (i < length_find) {
+ if (isalpha(find_str[i]) != 0) {
+ if (isupper(find_str[i]) != 0) {
+ look_ptr[i] = find_str[i];
+ } else {
+ look_ptr[i] = toupper(find_str[i]);
+ }
+ } else {
+ look_ptr[i] = find_str[i];
+ }
+
+ i++;
+ }
+
+ ret_ptr = strstr(org_ptr, look_ptr);
+
+ if (ret_ptr == 0) {
+ free(org_ptr);
+ free(look_ptr);
+ return NULL;
+ } else {
+ i = ret_ptr - org_ptr;
+ }
+
+ free(org_ptr);
+ free(look_ptr);
+
+ return (char*)(long_str + i);
+}
+
+/* This is not used. But it can be needed if there is no http header parser at http library.*/
+da_bool_t extract_attribute_from_header(
+ char *szHeadStr,
+ const char *szFindStr,
+ char **ppRtnValue)
+{
+
+ char *pValuePos = NULL;
+ int index = 0;
+ int startPos = 0;
+ int strLen = 0;
+ int need_to_end_quataion_mark = 0;
+
+ if (szHeadStr == DA_NULL || szFindStr == DA_NULL) {
+ DA_LOG_ERR(Default,"INVALID ARGUMENT");
+ return DA_FALSE;
+ }
+
+ if (strlen(szHeadStr) <= 0 || strlen(szFindStr) <= 0) {
+ DA_LOG_ERR(Default,"INVALID ARGUMENT");;
+
+ return DA_FALSE;
+ }
+
+ if (ppRtnValue == NULL) {
+ return DA_FALSE;
+ }
+
+ pValuePos = _stristr(szHeadStr, (char*)szFindStr);
+ if (pValuePos == NULL) {
+ *ppRtnValue = NULL;
+ goto ERR;
+ }
+
+ index = strlen(szFindStr);
+
+ while (pValuePos[index] != ':' && pValuePos[index] != '=') {
+ index++;
+
+ if (pValuePos[index] == '\0') {
+ return DA_FALSE;
+ }
+ }
+
+ index++;
+
+ /* jump space */
+ while (pValuePos[index] == ' ') {
+ index++;
+ }
+
+ /* jump quatation mark */
+ while (pValuePos[index] == '"') {
+ need_to_end_quataion_mark = 1;
+ index++;
+ }
+
+ startPos = index;
+
+ /* Find the end of data. */
+ if (0 == strncasecmp(szFindStr, "Location", strlen("Location")))//terminate character list does not contain ';' in case of URI
+ {
+ while (DA_FALSE == IS_URI_TERMINATING_CHAR(pValuePos[index])) {
+ index++;
+ }
+ } else if (need_to_end_quataion_mark) {
+ while (DA_FALSE == IS_TERMINATING_CHAR_EX(pValuePos[index])) {
+ index++;
+ }
+ } else {
+ while (DA_FALSE == IS_TERMINATING_CHAR(pValuePos[index])) {
+ index++;
+ }
+ }
+
+ strLen = index - startPos;
+
+ if (strLen < 1) {
+ DA_LOG_ERR(Default," strLen is < 1");
+ goto ERR;
+ }
+
+ *ppRtnValue = (char*)calloc(1, sizeof(char) * (strLen + 1));
+
+ if (*ppRtnValue == NULL) {
+ DA_LOG_ERR(Default," *ppRtnValue is NULL");
+ goto ERR;
+ }
+
+ strncpy(*ppRtnValue, pValuePos + startPos, strLen);
+ *(*ppRtnValue + strLen) = '\0';
+
+ return DA_TRUE;
+
+ERR:
+
+ if (*ppRtnValue) {
+ free(*ppRtnValue);
+ *ppRtnValue = NULL;
+ }
+
+ return DA_FALSE;
+}
+
diff --git a/agent/download-agent-http-queue.c b/agent/download-agent-http-queue.c
new file mode 100755
index 0000000..06fe084
--- /dev/null
+++ b/agent/download-agent-http-queue.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 "download-agent-http-queue.h"
+#include "download-agent-http-mgr.h"
+#include "download-agent-debug.h"
+#include "download-agent-pthread.h"
+
+void init_q_event_data_http(q_event_t *q_event);
+void init_q_event_control(q_event_t *q_event);
+
+void Q_init_queue(queue_t *queue)
+{
+ queue->having_data = DA_FALSE;
+ queue->control_head = DA_NULL;
+ queue->data_head = DA_NULL;
+ queue->queue_size = 0;
+
+ _da_thread_mutex_init(&(queue->mutex_queue), DA_NULL);
+ _da_thread_cond_init(&(queue->cond_queue), DA_NULL);
+}
+
+void Q_destroy_queue(queue_t *queue)
+{
+ q_event_t *event = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ do {
+ Q_pop_event(queue, &event);
+ Q_destroy_q_event(&event);
+ } while(event);
+
+ queue->having_data = DA_FALSE;
+ queue->control_head = DA_NULL;
+ queue->data_head = DA_NULL;
+ queue->queue_size = 0;
+
+ _da_thread_mutex_destroy(&(queue->mutex_queue));
+ _da_thread_cond_destroy(&(queue->cond_queue));
+}
+
+void Q_init_q_event(q_event_t *q_event)
+{
+ switch(q_event->event_type) {
+ case Q_EVENT_TYPE_DATA_HTTP:
+ init_q_event_data_http(q_event);
+ break;
+
+ case Q_EVENT_TYPE_DATA_DRM:
+ break;
+
+ case Q_EVENT_TYPE_CONTROL:
+ init_q_event_control(q_event);
+ break;
+ }
+
+ q_event->size = 0;
+ q_event->next = DA_NULL;
+}
+
+void Q_destroy_q_event(q_event_t **in_q_event)
+{
+ q_event_t *q_event = DA_NULL;
+ q_event = *in_q_event;
+
+ if(q_event == DA_NULL)
+ return;
+
+ switch(q_event->event_type) {
+ case Q_EVENT_TYPE_DATA_HTTP:
+ init_q_event_data_http(q_event);
+ q_event->size = 0;
+ q_event->next = DA_NULL;
+ free(q_event);
+ break;
+
+ case Q_EVENT_TYPE_DATA_DRM:
+ q_event->size = 0;
+ q_event->next = DA_NULL;
+ free(q_event);
+ break;
+
+ case Q_EVENT_TYPE_CONTROL:
+ init_q_event_control(q_event);
+ q_event->size = 0;
+ q_event->next = DA_NULL;
+ free(q_event);
+ break;
+ }
+}
+
+da_result_t Q_make_control_event(q_event_type_control control_type, q_event_t **out_event)
+{
+ da_result_t ret = DA_RESULT_OK;
+ q_event_t *q_event = DA_NULL;
+
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ q_event = (q_event_t *)calloc(1, sizeof(q_event_t));
+ if(q_event == DA_NULL) {
+ DA_LOG_ERR(HTTPManager, "calloc fail for q_event");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+
+ *out_event = DA_NULL;
+ } else {
+ q_event->event_type = Q_EVENT_TYPE_CONTROL;
+ q_event->type.q_event_control.control_type = control_type;
+ q_event->next = DA_NULL;
+
+ *out_event = q_event;
+ }
+
+ return ret;
+}
+
+da_result_t Q_make_http_data_event(q_event_type_data data_type, q_event_t **out_event)
+{
+ da_result_t ret = DA_RESULT_OK;
+ q_event_t *q_event = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ q_event = (q_event_t *)calloc(1, sizeof(q_event_t));
+ if(q_event == DA_NULL) {
+ DA_LOG_ERR(HTTPManager, "calloc fail for q_event");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ *out_event = DA_NULL;
+ } else {
+ q_event->event_type = Q_EVENT_TYPE_DATA_HTTP;
+ q_event->type.q_event_data_http.data_type = data_type;
+ q_event->next = DA_NULL;
+
+ *out_event = q_event;
+
+// DA_LOG_VERBOSE(HTTPManager, "made event = %x", *out_event);
+ }
+
+ return ret;
+
+}
+
+da_result_t Q_set_status_code_on_http_data_event(q_event_t *q_event, int status_code)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if(q_event->event_type != Q_EVENT_TYPE_DATA_HTTP) {
+ DA_LOG_ERR(HTTPManager, "status_code can be set only for Q_EVENT_TYPE_DATA_HTTP.");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+
+ q_event->type.q_event_data_http.status_code = status_code;
+
+// DA_LOG_VERBOSE(HTTPManager, "status_code = %d, q_event = %x", q_event->type.q_event_data_http.status_code, q_event);
+
+ERR:
+ return ret;
+
+}
+
+da_result_t Q_set_http_body_on_http_data_event(q_event_t *q_event, int body_len, char *body_data)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if(q_event->event_type != Q_EVENT_TYPE_DATA_HTTP) {
+ DA_LOG_ERR(HTTPManager, "http body can be set only for Q_EVENT_TYPE_DATA_HTTP.");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+
+ q_event->type.q_event_data_http.body_len = body_len;
+ q_event->type.q_event_data_http.body_data = body_data;
+ q_event->size = body_len;
+
+// DA_LOG_VERBOSE(HTTPManager, "body_len = %d, body_data = %x, q_event = %x", q_event->type.q_event_data_http.body_len, q_event->type.q_event_data_http.body_data, q_event);
+
+ERR:
+ return ret;
+
+}
+
+da_result_t Q_set_error_type_on_http_data_event(q_event_t *q_event, int error_type)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if(q_event->event_type != Q_EVENT_TYPE_DATA_HTTP) {
+ DA_LOG_ERR(HTTPManager, "error_type can be set only for Q_EVENT_TYPE_DATA_HTTP.");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+
+ q_event->type.q_event_data_http.error_type = error_type;
+
+ DA_LOG_VERBOSE(HTTPManager, "error_type = %d, q_event = %p", q_event->type.q_event_data_http.error_type, q_event);
+
+ERR:
+ return ret;
+
+}
+
+da_bool_t Q_push_event(const queue_t *in_queue, const q_event_t *in_event)
+{
+ da_bool_t b_ret = DA_FALSE;
+ queue_t *queue = (queue_t *)in_queue;
+
+ _da_thread_mutex_lock (&(queue->mutex_queue));
+ b_ret = Q_push_event_without_lock(in_queue, in_event);
+ _da_thread_mutex_unlock (&(queue->mutex_queue));
+
+ return b_ret;
+}
+
+da_bool_t Q_push_event_without_lock(const queue_t *in_queue, const q_event_t *in_event)
+{
+ da_bool_t b_ret = DA_FALSE;
+ queue_t *queue = (queue_t *)in_queue;
+ q_event_t *event = (q_event_t *)in_event;
+ q_event_type event_type;
+ q_event_t *head = DA_NULL;
+ q_event_t *cur = DA_NULL;
+
+// DA_LOG_VERBOSE(HTTPManager, "queue = %x", in_queue);
+
+ event_type = event->event_type;
+
+// _da_thread_mutex_lock (&(queue->mutex_queue));
+
+ if(event_type == Q_EVENT_TYPE_CONTROL) {
+ head = queue->control_head;
+ if(head == DA_NULL) {
+ queue->control_head = event;
+ } else {
+ cur = head;
+
+ while(cur->next != DA_NULL) {
+ cur = cur->next;
+ }
+ cur->next= event;
+ }
+ b_ret = DA_TRUE;
+ } else {
+ if((event->size == 0) || (queue->queue_size < MAX_QUEUE_SIZE)) {
+ head = queue->data_head;
+ if(head == DA_NULL) {
+ queue->data_head = event;
+ } else {
+ cur = head;
+ while(cur->next != DA_NULL) {
+ cur = cur->next;
+ }
+ cur->next= event ;
+ }
+
+ queue->queue_size += event->size;
+// DA_LOG_VERBOSE(HTTPManager, "queue size is %d", queue->queue_size);
+
+ b_ret = DA_TRUE;
+ } else {
+ DA_LOG_CRITICAL(HTTPManager, "rejected event's size is %d queue_size %d", event->size, queue->queue_size);
+ b_ret = DA_FALSE;
+ }
+ }
+
+ queue->having_data = DA_TRUE;
+ Q_wake_up(queue);
+// _da_thread_mutex_unlock (&(queue->mutex_queue));
+ return b_ret;
+}
+
+void Q_pop_event(const queue_t *in_queue, q_event_t **out_event)
+{
+ queue_t *queue = (queue_t*)in_queue;
+
+// DA_LOG_VERBOSE(HTTPManager, "queue = %x", in_queue);
+
+ /** Pop Priority
+ * 1. If there are control event, control event should pop first
+ * 2. If there is no control event, data event should pop
+ * 3. If there is no control and data event on queue, pop NULL
+ */
+
+ _da_thread_mutex_lock (&(queue->mutex_queue));
+
+ if(queue->control_head != DA_NULL) {/* Priority 1 */
+ *out_event = queue->control_head;
+ queue->control_head = queue->control_head->next;
+ } else {
+ if(queue->data_head != DA_NULL) {/* Priority 2 */
+ *out_event = queue->data_head;
+ queue->data_head = queue->data_head->next;
+ queue->queue_size -= (*out_event)->size;
+ DA_LOG_VERBOSE(HTTPManager, "queue size is %d", queue->queue_size);
+ } else {/* Priority 3 */
+ *out_event = DA_NULL;
+ }
+ }
+
+ if((queue->control_head == DA_NULL) && (queue->data_head == DA_NULL)) {
+ queue->having_data = DA_FALSE;
+ } else {
+ queue->having_data = DA_TRUE;
+ }
+
+ _da_thread_mutex_unlock (&(queue->mutex_queue));
+
+}
+
+void Q_goto_sleep(const queue_t *in_queue)
+{
+ DA_LOG_VERBOSE(HTTPManager, "sleep for %p", in_queue);
+
+//** SHOULD NOT use mutex **//
+
+// _da_thread_mutex_lock (&(in_queue->mutex_queue));
+ _da_thread_cond_wait((pthread_cond_t*)(&(in_queue->cond_queue)),(pthread_mutex_t*) (&(in_queue->mutex_queue)));
+// _da_thread_mutex_unlock (&(in_queue->mutex_queue));
+}
+
+void Q_wake_up(const queue_t *in_queue)
+{
+ DA_LOG_VERBOSE(HTTPManager, "wake up for %p", in_queue);
+
+//** SHOULD NOT use mutex **//
+
+// _da_thread_mutex_lock (&(in_queue->mutex_queue));
+ _da_thread_cond_signal((pthread_cond_t*)(&(in_queue->cond_queue)));
+// _da_thread_mutex_unlock (&(in_queue->mutex_queue));
+}
+
+void init_q_event_data_http(q_event_t *q_event)
+{
+ q_event_data_http_t *q_event_data_http;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if(q_event->event_type == Q_EVENT_TYPE_DATA_HTTP) {
+ q_event_data_http = &(q_event->type.q_event_data_http);
+
+ if(q_event_data_http) {
+ q_event_data_http->status_code = 0;
+ if(q_event_data_http->http_response_msg) {
+ http_msg_response_destroy(&(q_event_data_http->http_response_msg));
+ q_event_data_http->http_response_msg = DA_NULL;
+ }
+
+ if(q_event_data_http->body_len > 0 ) {
+ if (q_event_data_http->body_data) {
+ free(q_event_data_http->body_data);
+ q_event_data_http->body_data = DA_NULL;
+ }
+ }
+ q_event_data_http->error_type = 0;
+ }
+ }
+}
+
+void init_q_event_control(q_event_t *q_event)
+{
+ q_event_control_t *q_event_control;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if(q_event->event_type == Q_EVENT_TYPE_CONTROL) {
+ q_event_control = &(q_event->type.q_event_control);
+ if(q_event_control) {
+ q_event_control->control_type = Q_EVENT_TYPE_CONTROL_NONE;
+ }
+ }
+
+}
diff --git a/agent/download-agent-interface.c b/agent/download-agent-interface.c
new file mode 100755
index 0000000..7d994e6
--- /dev/null
+++ b/agent/download-agent-interface.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 "download-agent-interface.h"
+#include "download-agent-debug.h"
+#include "download-agent-utils.h"
+#include "download-agent-http-mgr.h"
+#include "download-agent-http-misc.h"
+#include "download-agent-client-mgr.h"
+#include "download-agent-dl-mgr.h"
+#include "download-agent-basic.h"
+#include "download-agent-file.h"
+
+int da_init(
+ da_client_cb_t *da_client_callback)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ DA_LOG_FUNC_LOGD(Default);
+
+ if (!da_client_callback) {
+ ret = DA_ERR_INVALID_ARGUMENT;
+ return ret;
+ }
+
+ ret = init_log_mgr();
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ ret = init_client_app_mgr();
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ ret = reg_client_app(da_client_callback);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ ret = init_http_mgr();
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ ret = init_download_mgr();
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ERR:
+ if (DA_RESULT_OK != ret)
+ da_deinit();
+
+ DA_LOG_CRITICAL(Default, "Return ret = %d", ret);
+
+ return ret;
+}
+
+/* TODO:: deinit should clean up all the clients... */
+int da_deinit()
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ deinit_http_mgr();
+ deinit_download_mgr();
+ /* Do not clean temporary download path
+ * The client can resume or restart download with temporary file in case of failed download.
+ */
+ dereg_client_app();
+ DA_LOG(Default, "====== da_deinit EXIT =====");
+
+ return ret;
+}
+
+int da_start_download(
+ const char *url,
+ int *download_id)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ DA_LOG_FUNC_LOGD(Default);
+
+ *download_id = DA_INVALID_ID;
+
+ if (DA_FALSE == is_valid_url(url, &ret))
+ goto ERR;
+
+ DA_SECURE_LOGI("url = %s", url);
+
+ ret = start_download(url, download_id);
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ERR:
+ DA_LOG_CRITICAL(Default, "Return: Dl req id = %d, ret = %d", *download_id, ret);
+ return ret;
+}
+
+int da_start_download_with_extension(
+ const char *url,
+ extension_data_t *extension_data,
+ int *download_id
+)
+{
+ da_result_t ret = DA_RESULT_OK;
+ int req_header_count = 0;
+ int i = 0;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ *download_id = DA_INVALID_ID;
+
+ if (DA_FALSE == is_valid_url(url, &ret))
+ goto ERR;
+
+ DA_SECURE_LOGI("url = %s", url);
+
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+ if (!extension_data) {
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+
+ if (extension_data->request_header_count > 0) {
+ DA_LOG_VERBOSE(Default, "input request_header_count = [%d]",
+ extension_data->request_header_count);
+ for (i = 0; i < extension_data->request_header_count; i++) {
+ if (extension_data->request_header[i]) {
+ req_header_count++;
+ DA_SECURE_LOGI("request_header = [%s]",
+ extension_data->request_header[i]);
+ }
+ }
+ DA_LOG_VERBOSE(Default, "actual request_header_count = [%d]", req_header_count);
+ if (extension_data->request_header_count != req_header_count) {
+ DA_LOG_ERR(Default, "Request header count is not matched with number of request header array");
+ extension_data->request_header = NULL;
+ extension_data->request_header_count = 0;
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+ }
+
+ if (extension_data->install_path) {
+ if (!is_dir_exist(extension_data->install_path))
+ return DA_ERR_INVALID_INSTALL_PATH;
+ DA_SECURE_LOGI("install_path = [%s]", extension_data->install_path);
+ }
+
+ if (extension_data->file_name)
+ DA_SECURE_LOGI("file_name = [%s]", extension_data->file_name);
+ if (extension_data->temp_file_path)
+ DA_SECURE_LOGI("temp_file_path = [%s]", extension_data->temp_file_path);
+ if (extension_data->etag)
+ DA_SECURE_LOGI("etag = [%s]", extension_data->etag);
+ if (extension_data->pkg_name)
+ DA_SECURE_LOGI("pkg_name = [%s]", extension_data->pkg_name);
+ if (extension_data->user_data)
+ DA_LOG_VERBOSE(Default, "user_data = [%p]", extension_data->user_data);
+
+ ret = start_download_with_extension(url, download_id, extension_data);
+
+ERR:
+ DA_LOG_CRITICAL(Default, "Return: Dl req id = %d, ret = %d", *download_id, ret);
+ return ret;
+}
+
+int da_cancel_download(int download_id)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ DA_LOG_VERBOSE(Default, "Cancel for dl_id = %d", download_id);
+
+ ret = cancel_download(download_id);
+
+ DA_LOG_CRITICAL(Default, "Return: Cancel id = %d, ret = %d", download_id, ret);
+ return ret;
+}
+
+int da_suspend_download(int download_id)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ DA_LOG_VERBOSE(Default, "Suspend for dl_id = %d", download_id);
+
+ ret = suspend_download(download_id, DA_TRUE);
+
+ DA_LOG_CRITICAL(Default, "Return: Suspend id = %d, ret = %d", download_id, ret);
+ return ret;
+}
+
+int da_suspend_download_without_update(int download_id)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ DA_LOG_VERBOSE(Default, "Suspend for dl_id = %d", download_id);
+
+ ret = suspend_download(download_id, DA_FALSE);
+
+ DA_LOG_CRITICAL(Default, "Return: Suspend id = %d, ret = %d", download_id, ret);
+ return ret;
+}
+
+
+int da_resume_download(int download_id)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ DA_LOG_VERBOSE(Default, "Resume for dl_id = %d", download_id);
+
+ ret = resume_download(download_id);
+
+ DA_LOG_CRITICAL(Default, "Return: Resume id = %d, ret = %d", download_id, ret);
+ return ret;
+}
+
+int da_is_valid_download_id(int download_id)
+{
+ da_bool_t ret = DA_FALSE;
+ ret = is_valid_download_id(download_id);
+ return ret;
+}
diff --git a/agent/download-agent-mime-util.c b/agent/download-agent-mime-util.c
new file mode 100755
index 0000000..53bab8b
--- /dev/null
+++ b/agent/download-agent-mime-util.c
@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <string.h>
+#include <stdlib.h>
+
+#include <xdgmime.h>
+
+#include "download-agent-debug.h"
+#include "download-agent-mime-util.h"
+#include "download-agent-pthread.h"
+
+#define IS_PROHIBITED_CHAR(c) ((c) == ';' || (c) == '\\' || (c) == '/' || (c) == ':' || (c) == '*' || (c) == '?' || (c) == '"' || (c) == '>' || (c) == '<' || (c) == '|' || (c) == '(' || (c) == ')')
+#define IS_SPACE_CHARACTER(c) ((c) == '\t')
+
+#define MAX_EXT_TABLE_INDEX 16
+Ext_translation_table ext_trans_table [MAX_EXT_TABLE_INDEX] = {
+ {"*.xla", "*.xls"},
+ {"*.pot", "*.ppt"},
+ {"*.xsl", "*.xml"},
+ {"*.spl", "*.swf"},
+ {"*.oga", "*.ogg"},
+ {"*.jpe", "*.jpg"},//5
+ {"*.CSSL", "*.css"},
+ {"*.htm", "*.html"},
+ {"*.hxx", "*.hpp"},
+ {"*.c++", "*.cpp"},
+ {"CMakeLists.txt", "*.cmake"},//10
+ {"*.ime", "*.imy"},
+ {"Makefile", "makefile"},
+ {"*.3g2", "*.3gp"},
+ {"*.mp2", "*.mpg"},
+ {"*.divx", "*.avi"},//15
+ };
+/* This is samsung mime policy
+ * 1. if the mime is audio/m4a, the extension name is defined as "m4a" for launching music player
+*/
+#ifdef _SAMSUNG_MIME_POLICY
+#define MAX_SEC_MIME_TABLE_INDEX 1
+struct sec_mime_table_t {
+ char *mime;
+ char *ext;
+};
+struct sec_mime_table_t sec_mime_table [MAX_SEC_MIME_TABLE_INDEX] = {
+ {"audio/m4a", "m4a"},
+};
+#endif
+
+const char *ambiguous_MIME_Type_list[] = {
+ "text/plain",
+ "application/octet-stream"
+};
+
+/* Because xdgmime is not thread safety, this mutex is necessary */
+pthread_mutex_t mutex_for_xdgmime = PTHREAD_MUTEX_INITIALIZER;
+
+da_bool_t is_ambiguous_MIME_Type(const char *in_mime_type)
+{
+ DA_LOG_FUNC_LOGV(Default);
+
+ if (!in_mime_type)
+ return DA_FALSE;
+
+ int index = 0;
+ int list_size = sizeof(ambiguous_MIME_Type_list) / sizeof(const char *);
+ for (index = 0 ; index < list_size ; index++) {
+ if (0 == strncmp(in_mime_type, ambiguous_MIME_Type_list[index],
+ strlen(ambiguous_MIME_Type_list[index]))) {
+ DA_SECURE_LOGD("It is ambiguous! [%s]", ambiguous_MIME_Type_list[index]);
+ return DA_TRUE;
+ }
+ }
+
+ return DA_FALSE;
+}
+
+da_result_t da_mime_get_ext_name(char *mime, char **ext)
+{
+ da_result_t ret = DA_RESULT_OK;
+ const char **extlist = DA_NULL;
+ const char *unaliased_mimetype = DA_NULL;
+ char ext_temp[DA_MAX_STR_LEN] = {0,};
+ char *temp = NULL;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ if (DA_NULL == mime || DA_NULL == ext) {
+ ret = DA_ERR_INVALID_ARGUMENT;
+ DA_LOG_ERR(Default,"Invalid mime type");
+ goto ERR;
+ }
+// DA_SECURE_LOGD("mime str[%s]ptr[%p]len[%d]",mime,mime,strlen(mime));
+ /* unaliased_mimetype means representative mime among similar types */
+ _da_thread_mutex_lock(&mutex_for_xdgmime);
+ unaliased_mimetype = xdg_mime_unalias_mime_type(mime);
+ _da_thread_mutex_unlock(&mutex_for_xdgmime);
+
+ if (unaliased_mimetype == DA_NULL) {
+ ret = DA_ERR_INVALID_MIME_TYPE;
+ DA_LOG_ERR(Default,"Invalid mime type : No unsaliased mime type");
+ goto ERR;
+ }
+ DA_SECURE_LOGD("unaliased_mimetype[%s]\n",unaliased_mimetype);
+
+ /* Get extension name from shared-mime-info */
+ _da_thread_mutex_lock(&mutex_for_xdgmime);
+ extlist = xdg_mime_get_file_names_from_mime_type(unaliased_mimetype);
+ _da_thread_mutex_unlock(&mutex_for_xdgmime);
+ if (extlist == DA_NULL || *extlist == DA_NULL) {
+ int i = 0;
+ ret = DA_ERR_INVALID_MIME_TYPE;
+ DA_LOG(Default,"No extension list");
+#ifdef _SAMSUNG_MIME_POLICY
+ for (i = 0; i < MAX_SEC_MIME_TABLE_INDEX; i++)
+ {
+ if (strncmp(sec_mime_table[i].mime, mime, strlen(mime)) == 0) {
+ strncpy(ext_temp, sec_mime_table[i].ext, DA_MAX_STR_LEN-1);
+ ret = DA_RESULT_OK;
+ break;
+ }
+ }
+#endif
+ } else { /* For drm case, this else statement is needed */
+ DA_SECURE_LOGD("extlist[%s]\n",*extlist);
+ strncpy(ext_temp, *extlist, DA_MAX_STR_LEN);
+ /* If only one extension name is existed, don't enter here */
+ while (*extlist != NULL) {
+ int i = 0;
+ /* If there are existed many extension names,
+ * try to search common extension name from table
+ * with first mime type at extension list*/
+ for (i = 0; i < MAX_EXT_TABLE_INDEX; i++)
+ {
+ if (strncmp(ext_trans_table[i].standard,*extlist,
+ strlen(*extlist)) == 0) {
+ memset(ext_temp, 0x00, DA_MAX_STR_LEN);
+ strncpy(ext_temp,ext_trans_table[i].normal, DA_MAX_STR_LEN-1);
+ break;
+ }
+ }
+ DA_LOG_VERBOSE(Default,"index[%d]\n",i);
+ /* If there is a mime at extension transform table */
+ if (i < MAX_EXT_TABLE_INDEX) {
+ break;
+ }
+ DA_SECURE_LOGD("extlist[%s]\n",*extlist);
+ extlist++;
+ }
+// DA_SECURE_LOGD("extension from shared mime info[%s]",ext_temp);
+ }
+
+ if (strlen(ext_temp) < 1) {
+ /* If there is no mime string for OMA descriptor mime type */
+ if (strncmp(DD_MIME_STR, mime, strlen(DD_MIME_STR)) == 0) {
+ strncpy(ext_temp, DD_EXT_STR, DA_MAX_STR_LEN-1);
+ ret = DA_RESULT_OK;
+ /* If there is no extension name for "applicaion/vnd.oma.drm.messeages"
+ * at shared-mime-info*/
+ } else if (strncmp(DRM_MIME_MSG_STR, mime,
+ strlen(DRM_MIME_MSG_STR)) == 0) {
+ strncpy(ext_temp, DRM_EXT_STR, DA_MAX_STR_LEN-1);
+ /* If there is extension name at extlist, the return value can have an error.*/
+ ret = DA_RESULT_OK;
+ } else {
+ ret = DA_ERR_INVALID_MIME_TYPE;
+ DA_LOG_ERR(Default,"Invalid mime type : no extension name at list");
+ }
+ }
+ if (ret != DA_RESULT_OK)
+ goto ERR;
+
+ temp = strchr(ext_temp,'.');
+ if (temp == NULL)
+ temp = ext_temp;
+ else
+ temp++;
+
+ *ext = (char*)calloc(1, strlen(temp) + 1);
+ if (*ext != DA_NULL) {
+ strncpy(*ext, temp,strlen(temp));
+ } else {
+ ret = DA_ERR_FAIL_TO_MEMALLOC ;
+ goto ERR ;
+ }
+ERR:
+ return ret;
+}
+
+da_bool_t da_get_extension_name_from_url(char *url, char **ext)
+{
+ da_bool_t ret = DA_TRUE;
+ char *buff = DA_NULL;
+ char *temp_str = DA_NULL;
+ int buf_len = 0;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ if (DA_NULL == url || DA_NULL == ext) {
+ ret = DA_FALSE;
+ DA_LOG_ERR(Default,"Invalid Argument");
+ return ret;
+ }
+
+ if ((temp_str = strrchr(url,'/'))) {
+ if ((buff = strrchr(temp_str,'.'))) {
+ char *q = DA_NULL;
+ buff++;
+ /* check to exist "?" after extension name */
+ q = strrchr(buff,'?');
+ if (q) {
+ buf_len = strlen(buff) - strlen(q);
+ } else {
+ buf_len = strlen(buff);
+ }
+ *ext = (char*) calloc(1, buf_len + 1) ;
+
+ if (DA_NULL == *ext) {
+ ret = DA_FALSE;
+ DA_LOG_ERR(Default,"Memory Fail");
+ goto ERR;
+ }
+ strncpy(*ext,buff,buf_len);
+ DA_SECURE_LOGD("extention name[%s]",*ext);
+ return ret;
+ }
+ }
+ERR:
+ if (*ext) {
+ free(*ext);
+ *ext = DA_NULL;
+ }
+ return ret;
+}
+
+/* FIXME move this function to another file */
+da_bool_t da_get_file_name_from_url(char *url, char **name)
+{
+ da_bool_t ret = DA_TRUE;
+ char *buff = DA_NULL;
+ char *Start = NULL;
+ char *End = NULL;
+ char c = 0;
+ int i = 0;
+ int j = 0;
+ int len_name = 0;
+ char name_buff[DA_MAX_FILE_PATH_LEN] = {0,};
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ if (DA_NULL == url || DA_NULL == name) {
+ ret = DA_FALSE;
+ DA_LOG_ERR(Default,"Invalid Argument");
+ goto ERR;
+ }
+ *name = DA_NULL;
+ if (!strstr(url, "http") && !strstr(url, "https")) {
+ ret = DA_FALSE;
+ DA_LOG_ERR(Default,"Invalid Argument");
+ goto ERR;
+ }
+
+ buff = (char*) calloc(1, strlen(url) +1);
+ if(DA_NULL == buff) {
+ ret = DA_FALSE;
+ DA_LOG_ERR(Default,"Memory Fail");
+ goto ERR;
+ }
+
+ while((c = url[i++]) != 0) {
+ if(c == '%') {
+ char buffer[3] = {0,};
+ buffer[0] = url[i++];
+ buffer[1] = url[i++];
+ buff[j++] = (char)strtol(buffer,NULL,16);
+ } else {
+ buff[j++] = c;
+ }
+ }
+ End = strstr(buff, "?");
+ if (DA_NULL != End) {
+ Start = End -1;
+ while(*(Start) != '/') {
+ Start--;
+ }
+ if ((*(Start) == '/') && ((len_name = (End - Start)) > 1)) {
+ Start++;
+ if (DA_MAX_FILE_PATH_LEN <= len_name) {
+ strncpy(name_buff, Start, DA_MAX_FILE_PATH_LEN-1);
+ name_buff[DA_MAX_FILE_PATH_LEN-1] = '\0';
+ } else {
+ strncpy(name_buff, Start, len_name);
+ name_buff[len_name] = '\0';
+ }
+ } else {
+ ret = DA_FALSE;
+ goto ERR ; /*Name not found*/
+ }
+ } else {
+ int urlLen = strlen (buff);
+ int Start_pos = 0;
+ Start_pos = urlLen - 1;
+
+ while(Start_pos > 0) {
+ if(buff[Start_pos] == '/')
+ break;
+ Start_pos--;
+ }
+ Start_pos++;
+ if (Start_pos == 0 || urlLen - Start_pos <= 0) {
+ ret = DA_FALSE;
+ goto ERR;
+ }
+ while(Start_pos < urlLen) {
+ name_buff[len_name++] = buff[Start_pos++];
+ if (DA_MAX_FILE_PATH_LEN <= len_name) {
+ name_buff[DA_MAX_FILE_PATH_LEN-1] ='\0';
+ break;
+ }
+ }
+ }
+
+ if (len_name) {
+ End = strrchr(name_buff, '.');
+ if (End != NULL) {
+ *End = '\0';
+ }
+// DA_SECURE_LOGD("file name BEFORE removing prohibited character = %s", name_buff);
+ delete_prohibited_char(name_buff, strlen(name_buff));
+// DA_SECURE_LOGD("file name AFTER removing prohibited character = %s", name_buff);
+ len_name = strlen(name_buff);
+ *name = (char*) calloc(1, len_name + 1);
+ if (*name) {
+ strncpy(*name, name_buff,len_name);
+ }
+ }
+// DA_SECURE_LOGD("Extracted file name : %s", *name);
+ERR:
+ if (buff) {
+ free (buff);
+ buff = DA_NULL;
+ }
+ return ret;
+}
+
+void delete_prohibited_char(char *szTarget, int str_len)
+{
+ char *chk_str = NULL;
+ int i = 0;
+ int j = 0;
+ int tar_len = 0;
+
+ if(szTarget == NULL || str_len <= 0 || strlen(szTarget) != str_len) {
+ DA_LOG_ERR(Default,"Invaild Parameter\n");
+ return;
+ }
+
+ chk_str = (char *)calloc(1, str_len + 1);
+ if(chk_str == NULL)
+ return;
+
+ while(szTarget[j] != '\0') {
+ if(IS_PROHIBITED_CHAR(szTarget[j]) == DA_FALSE &&
+ IS_SPACE_CHARACTER(szTarget[j]) == DA_FALSE) {
+ chk_str[i] = szTarget[j];
+ i++;
+ }
+ j++;
+ }
+
+ chk_str[i] = '\0';
+ tar_len = strlen(chk_str);
+
+ if(tar_len <= 0)
+ szTarget[0] = '\0';
+ else {
+ for(i = 0; i < tar_len; i++)
+ {
+ szTarget[i] = chk_str[i];
+ }
+ szTarget[i] = '\0';
+ }
+
+ if(chk_str != NULL) {
+ free(chk_str);
+ }
+ return;
+}
+
diff --git a/agent/download-agent-plugin-conf.c b/agent/download-agent-plugin-conf.c
new file mode 100755
index 0000000..8a547f7
--- /dev/null
+++ b/agent/download-agent-plugin-conf.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <string.h>
+#include <stdlib.h>
+#include <glib-object.h>
+
+#ifdef _EFL_PLATFORM
+#include <vconf.h>
+#include <vconf-keys.h>
+#include <net_connection.h>
+#endif /* _EFL_PLATFORM */
+
+#include "download-agent-plugin-conf.h"
+#include "download-agent-debug.h"
+#include "download-agent-file.h"
+
+#define DEFAULT_UA_STR "Mozilla/5.0 (Linux; U; Tizen 1.0; en-us) AppleWebKit/534.46 (KHTML, like Gecko) Mobile Tizen Browser/1.0"
+
+da_result_t __get_conf_string(const char *key, char **out_string);
+
+da_result_t __get_conf_string(const char *key, char **out_string)
+{
+#ifdef _EFL_PLATFORM
+ if (!key || !out_string) {
+ DA_LOG_ERR(Default,"Invalid Argument");
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+
+ *out_string = vconf_get_str(key);
+ return DA_RESULT_OK;
+#else
+ if (out_string)
+ *out_string = NULL;
+
+ return DA_RESULT_OK;
+#endif
+}
+
+da_result_t get_user_agent_string(char **uagent_str)
+{
+ da_result_t ret = DA_RESULT_OK;
+#ifdef _EFL_PLATFORM
+ char *key = DA_NULL;
+#endif
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ if (!uagent_str) {
+ DA_LOG_ERR(Default,"Invalid Argument");
+ return DA_ERR_INVALID_ARGUMENT;
+ }
+
+#ifdef _EFL_PLATFORM
+ key = VCONFKEY_BROWSER_USER_AGENT;
+ ret = __get_conf_string(key, uagent_str);
+ if(ret == DA_RESULT_OK) {
+ if(*uagent_str) {
+ DA_SECURE_LOGD("getting uagent_str = \n%s", *uagent_str);
+ return ret;
+ }
+ }
+ DA_LOG_ERR(Default,"No UA information from vconf !!");
+ *uagent_str = strdup(DEFAULT_UA_STR);
+ DA_LOG(Default,"Set default UA");
+#else
+ *uagent_str = strdup(DEFAULT_UA_STR);
+#endif
+ return ret;
+}
+
+char *get_proxy_address(void)
+{
+#ifdef _EFL_PLATFORM
+ char *proxy = NULL;
+ char *proxyRet = NULL;
+ connection_h handle = NULL;
+ connection_address_family_e family = CONNECTION_ADDRESS_FAMILY_IPV4;
+
+ DA_LOG_FUNC_LOGV(Default);
+ if (connection_create(&handle) < 0) {
+ DA_LOG_ERR(Default,"Fail to create connection handle");
+ return NULL;
+ }
+
+ if (connection_get_proxy(handle, family, &proxyRet) < 0) {
+ DA_LOG_ERR(Default,"Fail to get proxy address");
+ connection_destroy(handle);
+ return NULL;
+ }
+
+ if (proxyRet) {
+ DA_SECURE_LOGD("===== Proxy address[%s] =====", proxyRet);
+ proxy = strdup(proxyRet);
+ free(proxyRet);
+ proxyRet = NULL;
+ connection_destroy(handle);
+ return proxy;
+ }
+
+ if (connection_destroy(handle) < 0) {
+ DA_LOG_ERR(Default,"Fail to desctory connection handle");
+ return NULL;
+ }
+ return NULL;
+#else
+ return NULL;
+#endif
+}
diff --git a/agent/download-agent-plugin-libsoup.c b/agent/download-agent-plugin-libsoup.c
new file mode 100755
index 0000000..6d54afd
--- /dev/null
+++ b/agent/download-agent-plugin-libsoup.c
@@ -0,0 +1,1002 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+#include "download-agent-debug.h"
+#include "download-agent-plugin-libsoup.h"
+#include "download-agent-http-misc.h"
+#include "download-agent-utils.h"
+#include "download-agent-pthread.h"
+
+pthread_mutex_t mutex_for_session_table = PTHREAD_MUTEX_INITIALIZER;
+
+pi_session_table_t pi_session_table[MAX_SESSION_COUNT] = { { 0, }, };
+da_bool_t using_content_sniffing;
+
+da_bool_t _pi_http_is_this_session_table_entry_using(
+ const int in_session_table_entry);
+
+da_result_t PI_http_init(void)
+{
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ using_content_sniffing = DA_TRUE;
+
+ return DA_RESULT_OK;
+}
+
+void PI_http_deinit(void)
+{
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ return;
+}
+
+da_result_t _set_proxy_on_soup_session(SoupSession *session, char *proxy_addr)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+
+ if (proxy_addr && strlen(proxy_addr) > 0) {
+ DA_SECURE_LOGD("received proxy = %s \n", proxy_addr);
+ if (!strstr(proxy_addr, "0.0.0.0")) {
+ if (strstr((const char *)proxy_addr, "http") == DA_NULL) {
+ DA_LOG_VERBOSE(Default,"There is no \"http://\" on received uri, so, add it.");
+
+ char *tmp_str = DA_NULL;
+ int needed_len = 0;
+
+ needed_len = strlen(proxy_addr) + strlen(
+ SCHEME_HTTP) + 1;
+ tmp_str = (char *) calloc(1, needed_len);
+ if (!tmp_str) {
+ DA_LOG_ERR(HTTPManager,"DA_ERR_FAIL_TO_MEMALLOC");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ }
+ snprintf(tmp_str, needed_len, "%s%s",
+ SCHEME_HTTP, proxy_addr);
+
+ g_object_set(session, SOUP_SESSION_PROXY_URI,
+ soup_uri_new(tmp_str), NULL);
+
+ free(tmp_str);
+ } else {
+ DA_LOG(HTTPManager,"There is \"http\" on uri, so, push this address to soup directly.");
+ g_object_set(session, SOUP_SESSION_PROXY_URI,
+ soup_uri_new(proxy_addr), NULL);
+ }
+ }
+ } else {
+ DA_LOG_VERBOSE(HTTPManager,"There is no proxy value");
+ }
+ERR:
+ return ret;
+}
+
+void _fill_soup_msg_header(SoupMessage *msg,
+ const input_for_tranx_t *input_for_tranx)
+{
+ SoupMessageHeaders *headers = msg->request_headers;
+
+ http_msg_request_t *input_http_msg_request;
+ http_msg_iter_t http_msg_iter;
+ http_msg_iter_t http_msg_iter_pre;
+
+ char *field;
+ char *value;
+
+ input_http_msg_request = input_for_tranx->http_msg_request;
+
+ http_msg_request_get_iter(input_http_msg_request, &http_msg_iter);
+ http_msg_iter_pre = http_msg_iter;
+ while (http_msg_get_field_with_iter(&http_msg_iter, &field, &value)) {
+ if ((field != DA_NULL) && (value != DA_NULL)) {
+ DA_SECURE_LOGD("[%s] %s", field, value);
+ soup_message_headers_append(headers, field, value);
+ }
+ http_msg_iter_pre = http_msg_iter;
+ }
+
+ if (input_http_msg_request->http_body) {
+ char body_len_str[16] = { 0, };
+ int body_len = strlen(input_http_msg_request->http_body);
+
+ snprintf(body_len_str, sizeof(body_len_str), "%d", body_len);
+
+ soup_message_headers_append(headers, "Content-Length",
+ body_len_str);
+ soup_message_headers_append(headers, "Content-Type",
+ "text/plain");
+ soup_message_body_append(msg->request_body, SOUP_MEMORY_COPY,
+ input_http_msg_request->http_body, body_len);
+ }
+}
+
+da_result_t PI_http_start_transaction(const input_for_tranx_t *input_for_tranx,
+ int *out_tranx_id)
+{
+ da_result_t ret = DA_RESULT_OK;
+ int session_table_entry = -1;
+ pi_http_method_t pi_http_method = PI_HTTP_METHOD_GET;
+ queue_t *queue = DA_NULL;
+ char *url = DA_NULL;
+ SoupSession *session = DA_NULL;
+ SoupMessage *msg = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (DA_FALSE == _pi_http_is_valid_input_for_tranx(input_for_tranx)) {
+ DA_LOG_ERR(HTTPManager,"input_for_tranx is invalid");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ } else {
+ queue = input_for_tranx->queue;
+ pi_http_method = input_for_tranx->http_method;
+ url = input_for_tranx->http_msg_request->url;
+ }
+
+ session_table_entry = _pi_http_get_avaiable_session_table_entry();
+ if (session_table_entry == -1) {
+ ret = DA_ERR_ALREADY_MAX_DOWNLOAD;
+ goto ERR;
+ }
+ DA_LOG_VERBOSE(HTTPManager,"session_table_entry = %d", session_table_entry);
+
+ if (DA_FALSE == _pi_http_register_queue_to_session_table(
+ session_table_entry, queue)) {
+ _pi_http_destroy_session_table_entry(session_table_entry);
+ ret = DA_ERR_ALREADY_MAX_DOWNLOAD;
+ goto ERR;
+ }
+
+ /* modified by keunsoon.lee 2010-09-20 use sync_new() instead of async_new() for make different soup thread from UI main thread*/
+ session = soup_session_sync_new();
+ /* session=soup_session_async_new(); */
+ if (!session) {
+ DA_LOG_ERR(HTTPManager,"Fail to create session");
+ return DA_ERR_INVALID_URL;
+ }
+ DA_LOG(HTTPManager,"session[%p]", session);
+/*
+ SoupLogger* logger = soup_logger_new(SOUP_LOGGER_LOG_BODY, -1);
+ soup_logger_attach(logger, session);
+ g_object_unref(logger);
+*/
+ if (DA_FALSE == _pi_http_register_session_to_session_table(
+ session_table_entry, session)) {
+ _pi_http_init_session_table_entry(session_table_entry);
+ ret = DA_ERR_ALREADY_MAX_DOWNLOAD;
+ goto ERR;
+ }
+
+ g_object_set(session, SOUP_SESSION_MAX_CONNS, MAX_SESSION_COUNT, NULL);
+ /* Set timeout unlimited time to resume a download which has ETag when the network is re-connected
+ * => This is changed to 180 seconds due to limitation of max downloading items.
+ */
+ g_object_set(session, SOUP_SESSION_TIMEOUT, MAX_TIMEOUT, NULL);
+
+ _set_proxy_on_soup_session(session, input_for_tranx->proxy_addr);
+
+ switch (pi_http_method) {
+ case PI_HTTP_METHOD_GET:
+ msg = soup_message_new(METHOD_GET, url);
+ break;
+ case PI_HTTP_METHOD_POST:
+ msg = soup_message_new(METHOD_POST, url);
+ break;
+ case PI_HTTP_METHOD_HEAD:
+ msg = soup_message_new(METHOD_HEAD, url);
+ break;
+ default:
+ DA_LOG_ERR(HTTPManager,"Cannot enter here");
+ break;
+ }
+ DA_LOG_VERBOSE(HTTPManager,"msg[%p]", msg);
+ /* if it is failed to create a msg, the url can be invalid, becasue of the input argument of soup_message_new API */
+ if (msg == NULL) {
+ DA_LOG_ERR(HTTPManager,"Fail to create message");
+ ret = DA_ERR_INVALID_URL;
+ goto ERR;
+ }
+
+ _fill_soup_msg_header(msg, input_for_tranx);
+
+ g_signal_connect(msg, "restarted", G_CALLBACK(_pi_http_restarted_cb),
+ NULL); /* for redirection case */
+ g_signal_connect(msg, "got-headers",
+ G_CALLBACK(_pi_http_gotheaders_cb), NULL);
+ g_signal_connect(msg, "got-chunk", G_CALLBACK(_pi_http_gotchunk_cb),
+ NULL);
+
+ if (using_content_sniffing) {
+ soup_session_add_feature_by_type(session, SOUP_TYPE_CONTENT_SNIFFER);
+ g_signal_connect(msg, "content-sniffed",
+ G_CALLBACK(_pi_http_contentsniffed_cb), NULL);
+ } else {
+ soup_message_disable_feature(msg, SOUP_TYPE_CONTENT_SNIFFER);
+ }
+
+ soup_session_queue_message(session, msg, _pi_http_finished_cb, NULL);
+// g_signal_connect(msg, "finished", G_CALLBACK(_pi_http_finished_cb), NULL);
+
+ if (DA_FALSE == _pi_http_register_msg_to_session_table(
+ session_table_entry, msg)) {
+ _pi_http_destroy_session_table_entry(session_table_entry);
+ ret = DA_ERR_ALREADY_MAX_DOWNLOAD;
+ goto ERR;
+ }
+
+ *out_tranx_id = session_table_entry;
+ DA_LOG(HTTPManager,"*out_tranx_id = %d", *out_tranx_id);
+
+ERR:
+ return ret;
+}
+
+da_result_t PI_http_disconnect_transaction(int in_tranx_id)
+{
+ da_result_t ret = DA_RESULT_OK;
+ int session_table_entry = -1;
+
+ DA_LOG_VERBOSE(HTTPManager,"in_tranx_id = %d", in_tranx_id);
+
+ session_table_entry = in_tranx_id;
+
+ _pi_http_destroy_session_table_entry(session_table_entry);
+
+ return ret;
+}
+
+da_result_t PI_http_cancel_transaction(int in_tranx_id, da_bool_t abort_option)
+{
+ da_result_t ret = DA_RESULT_OK;
+ SoupSession *session;
+ SoupMessage *msg;
+ int session_table_entry = -1;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ session_table_entry = in_tranx_id;
+ if (!_pi_http_is_this_session_table_entry_using(session_table_entry)) {
+ DA_LOG_CRITICAL(HTTPManager,"not using session");
+ return ret;
+ }
+ session = GET_SESSION_FROM_TABLE_ENTRY(session_table_entry);
+ msg = GET_MSG_FROM_TABLE_ENTRY(session_table_entry);
+
+ if (DA_NULL == session) {
+ DA_LOG_ERR(HTTPManager,"invalid session = %p", session);
+ goto ERR;
+ }
+
+ if (DA_NULL == msg) {
+ DA_LOG_ERR(HTTPManager,"invalid message = %p", msg);
+ goto ERR;
+ }
+ DA_LOG(HTTPManager,"soup cancel API:abort option[%d] tranx_id[%d]",
+ abort_option, in_tranx_id);
+ if (abort_option)
+ soup_session_abort(session);
+ else
+ soup_session_cancel_message(session, msg, SOUP_STATUS_CANCELLED);
+ DA_LOG(HTTPManager,"soup cancel API-Done");
+ERR:
+ return ret;
+}
+
+void PI_http_pause_transaction(int transaction_id)
+{
+ int session_table_entry = -1;
+ pthread_mutex_t *mutex;
+ pthread_cond_t *cond;
+
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ DA_LOG(HTTPManager,"in_tranx_id = %d", transaction_id);
+
+ session_table_entry = transaction_id;
+
+ if (!_pi_http_is_this_session_table_entry_using(session_table_entry))
+ return;
+
+ mutex = &(pi_session_table[session_table_entry].mutex);
+ cond = &(pi_session_table[session_table_entry].cond);
+
+ _da_thread_mutex_lock (mutex);
+
+ if (pi_session_table[session_table_entry].is_paused == DA_FALSE) {
+ DA_LOG_CRITICAL(HTTPManager,"paused!");
+ pi_session_table[session_table_entry].is_paused = DA_TRUE;
+ _da_thread_cond_wait(cond, mutex);
+ } else {
+ DA_LOG_CRITICAL(HTTPManager,"NOT paused!");
+ }
+
+ _da_thread_mutex_unlock (mutex);
+
+}
+
+void PI_http_unpause_transaction(int transaction_id)
+{
+ int session_table_entry = -1;
+ pthread_mutex_t *mutex;
+ pthread_cond_t *cond;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ session_table_entry = transaction_id;
+
+ if (!_pi_http_is_this_session_table_entry_using(session_table_entry))
+ return;
+
+ mutex = &(pi_session_table[session_table_entry].mutex);
+ cond = &(pi_session_table[session_table_entry].cond);
+
+ _da_thread_mutex_lock (mutex);
+
+ if (pi_session_table[session_table_entry].is_paused == DA_TRUE) {
+ DA_LOG_CRITICAL(HTTPManager,"wake up!");
+ pi_session_table[session_table_entry].is_paused = DA_FALSE;
+ _da_thread_cond_signal(cond);
+ }
+
+ _da_thread_mutex_unlock (mutex);
+
+}
+
+da_bool_t _pi_http_is_valid_input_for_tranx(
+ const input_for_tranx_t *input_for_tranx)
+{
+ if (!(input_for_tranx->http_msg_request)) {
+ DA_LOG_ERR(HTTPManager,"http_msg_request is NULL");
+ return DA_FALSE;
+ }
+
+ if (!((input_for_tranx->http_method == PI_HTTP_METHOD_GET) ||
+ (input_for_tranx->http_method == PI_HTTP_METHOD_POST) ||
+ (input_for_tranx->http_method == PI_HTTP_METHOD_HEAD))) {
+ DA_LOG_ERR(HTTPManager,"http_method is neither GET or POST or HEAD");
+ return DA_FALSE;
+ }
+
+ return DA_TRUE;
+}
+
+da_bool_t _pi_http_is_this_session_table_entry_using(
+ const int in_session_table_entry)
+{
+ da_bool_t is_using = DA_FALSE;
+
+ if (DA_FALSE == IS_VALID_SESSION_TABLE_ENTRY(in_session_table_entry))
+ return DA_FALSE;
+
+ _da_thread_mutex_lock (&mutex_for_session_table);
+
+ is_using = pi_session_table[in_session_table_entry].is_using;
+
+ _da_thread_mutex_unlock (&mutex_for_session_table);
+
+ return is_using;
+}
+
+void _pi_http_init_session_table_entry(const int in_session_table_entry)
+{
+ int entry = in_session_table_entry;
+
+ if (DA_FALSE == IS_VALID_SESSION_TABLE_ENTRY(entry))
+ return;
+
+// _da_thread_mutex_lock (&mutex_for_session_table);
+
+ pi_session_table[entry].is_using = DA_TRUE;
+ pi_session_table[entry].msg = NULL;
+ pi_session_table[entry].session = NULL;
+ pi_session_table[entry].queue = NULL;
+
+ _da_thread_mutex_init(&(pi_session_table[entry].mutex), DA_NULL);
+ _da_thread_cond_init(&(pi_session_table[entry].cond), NULL);
+ pi_session_table[entry].is_paused = DA_FALSE;
+
+// _da_thread_mutex_unlock (&mutex_for_session_table);
+
+ return;
+}
+
+void _pi_http_destroy_session_table_entry(const int in_session_table_entry)
+{
+ int entry = in_session_table_entry;
+
+ if (DA_FALSE == IS_VALID_SESSION_TABLE_ENTRY(entry))
+ return;
+
+ _da_thread_mutex_lock (&mutex_for_session_table);
+
+ if (pi_session_table[entry].is_paused == DA_TRUE)
+ PI_http_unpause_transaction(entry);
+
+ /* Warning! Do not g_object_unref(msg) here!
+ * soup_session_queue_message() steals msg's reference count,
+ * so, we don't need to do anything for memory management.
+ *
+ * But, if using soup_session_send_message(), MUST call g_object_unref(msg). */
+ /* if (pi_session_table[entry].msg)
+ g_object_unref(pi_session_table[entry].msg); */
+
+ pi_session_table[entry].msg = NULL;
+
+ /* FIXME Cannot g_object_unref(session) here,
+ * because msg inside this session is not destoryed yet.
+ * The msg's reference count is stealed by soup_session_queue_message(),
+ * and it will be destroyed when _pi_http_finished_cb() is returned.
+ * For now, this _pi_http_destroy_session_table_entry() is called inside
+ * _pi_http_finished_cb(), so, g_object_unref(session) is not working.
+ * Should find out call this function after _pi_http_finished_cb(). */
+ if (pi_session_table[entry].session)
+ g_object_unref(pi_session_table[entry].session);
+ else
+ DA_LOG_ERR(HTTPManager,"session is NULL. Cannot unref this.");
+ DA_LOG(HTTPManager,"unref session [%p]",pi_session_table[entry].session);
+
+ pi_session_table[entry].session = NULL;
+
+ pi_session_table[entry].queue = NULL;
+ pi_session_table[entry].is_paused = DA_FALSE;
+ pi_session_table[entry].is_using = DA_FALSE;
+
+ _da_thread_mutex_destroy(&(pi_session_table[entry].mutex));
+ _da_thread_cond_destroy(&(pi_session_table[entry].cond));
+
+ _da_thread_mutex_unlock (&mutex_for_session_table);
+
+ return;
+}
+
+int _pi_http_get_avaiable_session_table_entry(void)
+{
+ int i;
+ int avaiable_entry = -1;
+
+ _da_thread_mutex_lock (&mutex_for_session_table);
+
+ for (i = 0; i < MAX_SESSION_COUNT; i++) {
+ if (pi_session_table[i].is_using == DA_FALSE) {
+ /* pi_session_table[i].is_using = DA_TRUE; */
+ DA_LOG_VERBOSE(HTTPManager,"available entry = %d", i);
+
+ avaiable_entry = i;
+
+ break;
+ }
+ }
+ _pi_http_init_session_table_entry(avaiable_entry);
+ _da_thread_mutex_unlock (&mutex_for_session_table);
+
+ return avaiable_entry;
+}
+
+da_bool_t _pi_http_register_queue_to_session_table(
+ const int in_session_table_entry, const queue_t *in_queue)
+{
+ int entry = in_session_table_entry;
+ queue_t *queue = (queue_t *) in_queue;
+ da_bool_t ret = DA_FALSE;
+
+ if (DA_FALSE == IS_VALID_SESSION_TABLE_ENTRY(entry)) {
+ DA_LOG_ERR(HTTPManager,"invalid entry = %d", entry);
+ return DA_FALSE;
+ }
+
+ _da_thread_mutex_lock (&mutex_for_session_table);
+
+ if (pi_session_table[entry].is_using == DA_FALSE) {
+ DA_LOG_ERR(HTTPManager,"this entry [%d] is not using", entry);
+ ret = DA_FALSE;
+ } else {
+ pi_session_table[entry].queue = queue;
+ DA_LOG_VERBOSE(HTTPManager,"queue = %p", pi_session_table[entry].queue);
+ ret = DA_TRUE;
+ }
+
+ _da_thread_mutex_unlock (&mutex_for_session_table);
+
+ return ret;
+}
+
+da_bool_t _pi_http_register_session_to_session_table(
+ const int in_session_table_entry, SoupSession *session)
+{
+ int entry = in_session_table_entry;
+ da_bool_t ret = DA_FALSE;
+
+ if (DA_FALSE == IS_VALID_SESSION_TABLE_ENTRY(entry)) {
+ DA_LOG_ERR(HTTPManager,"invalid entry = %d", entry);
+ return DA_FALSE;
+ }
+
+ if (DA_NULL == session) {
+ DA_LOG_ERR(HTTPManager,"invalid session = %p",session);
+ return DA_FALSE;
+ }
+
+ _da_thread_mutex_lock (&mutex_for_session_table);
+
+ if (pi_session_table[entry].is_using == DA_FALSE) {
+ ret = DA_FALSE;
+ } else {
+ pi_session_table[entry].session = session;
+ ret = DA_TRUE;
+ }
+
+ _da_thread_mutex_unlock (&mutex_for_session_table);
+
+ return ret;
+}
+
+da_bool_t _pi_http_register_msg_to_session_table(
+ const int in_session_table_entry, SoupMessage *msg)
+{
+ int entry = in_session_table_entry;
+ da_bool_t ret = DA_FALSE;
+
+ if (DA_FALSE == IS_VALID_SESSION_TABLE_ENTRY(entry)) {
+ DA_LOG_ERR(HTTPManager,"invalid entry = %d", entry);
+ return DA_FALSE;
+ }
+
+ if (DA_NULL == msg) {
+ DA_LOG_ERR(HTTPManager,"invalid msg = %p",msg);
+ return DA_FALSE;
+ }
+
+ _da_thread_mutex_lock (&mutex_for_session_table);
+
+ if (pi_session_table[entry].is_using == DA_FALSE) {
+ ret = DA_FALSE;
+ } else {
+ pi_session_table[entry].msg = msg;
+ ret = DA_TRUE;
+ }
+
+ _da_thread_mutex_unlock (&mutex_for_session_table);
+
+ return ret;
+}
+
+queue_t *_pi_http_get_queue_from_session_table_entry(
+ const int in_session_table_entry)
+{
+ int entry = in_session_table_entry;
+ queue_t *out_queue = NULL;
+
+ if (DA_FALSE == IS_VALID_SESSION_TABLE_ENTRY(entry)) {
+ DA_LOG_ERR(HTTPManager,"invalid entry = %d", entry);
+ return out_queue;
+ }
+
+ _da_thread_mutex_lock (&mutex_for_session_table);
+
+ out_queue = pi_session_table[entry].queue;
+ _da_thread_mutex_unlock (&mutex_for_session_table);
+
+ return out_queue;
+}
+
+void _pi_http_store_read_header_to_queue(SoupMessage *msg, const char *sniffedType)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ queue_t *da_queue = NULL;
+ q_event_t *da_event = NULL;
+ q_event_type_data da_event_type_data;
+
+ int session_table_entry = -1;
+ SoupMessageHeadersIter headers_iter;
+
+ const char *header_name;
+ const char *header_value;
+
+ http_msg_response_t *http_msg_response = NULL;
+
+ if (msg->response_headers) {
+ ret = http_msg_response_create(&http_msg_response);
+ if (ret != DA_RESULT_OK)
+ return;
+
+ http_msg_response_set_status_code(http_msg_response,
+ msg->status_code);
+
+ DA_LOG_VERBOSE(HTTPManager,"\n----raw header---------------------------------------------");
+ DA_LOG(HTTPManager,"status code = %d", msg->status_code);
+ soup_message_headers_iter_init(&headers_iter,
+ msg->response_headers);
+ while (soup_message_headers_iter_next(&headers_iter,
+ &header_name, &header_value)) {
+ if ((header_name != DA_NULL) && (header_value
+ != DA_NULL)) {
+ http_msg_response_add_field(http_msg_response,
+ header_name, header_value);
+ DA_SECURE_LOGI("[%s][%s]", header_name, header_value);
+ }
+ }
+ DA_LOG_VERBOSE(HTTPManager,"\n-------------------------------------------------------------\n");
+
+ }
+
+ if (using_content_sniffing && sniffedType)
+ http_msg_response_set_content_type(http_msg_response, sniffedType);
+
+ session_table_entry
+ = _pi_http_get_session_table_entry_from_message(msg);
+ if (session_table_entry == -1) {
+ DA_LOG_ERR(HTTPManager,"Fail to find matched session table entry..");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+
+ da_event_type_data = Q_EVENT_TYPE_DATA_PACKET;
+
+ da_queue = _pi_http_get_queue_from_session_table_entry(
+ session_table_entry);
+
+ ret = Q_make_http_data_event(da_event_type_data, &da_event);
+ if (ret != DA_RESULT_OK) {
+ DA_LOG_ERR(HTTPManager,"fail to make da_event");
+ goto ERR;
+ } else {
+ Q_set_status_code_on_http_data_event(da_event, msg->status_code);
+ da_event->type.q_event_data_http.http_response_msg
+ = http_msg_response;
+
+ Q_push_event(da_queue, da_event);
+ }
+ return;
+
+ERR:
+ if (DA_RESULT_OK != ret)
+ http_msg_response_destroy(&http_msg_response);
+
+ return;
+}
+
+void _pi_http_store_read_data_to_queue(SoupMessage *msg, const char *body_data,
+ int received_body_len)
+{
+ da_result_t ret = DA_RESULT_OK;
+ da_bool_t b_ret = DA_FALSE;
+
+ char *body_buffer = NULL;
+ queue_t *da_queue = NULL;
+ q_event_t *da_event = NULL;
+ q_event_type_data da_event_type_data;
+ int session_table_entry = -1;
+ int http_status = -1;
+
+ http_status = msg->status_code;
+
+ session_table_entry
+ = _pi_http_get_session_table_entry_from_message(msg);
+ if (session_table_entry == -1) {
+ DA_LOG_ERR(HTTPManager,"Fail to find matched session table entry..");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+
+ if (received_body_len == 0) {
+ DA_LOG_VERBOSE(HTTPManager,"Q_EVENT_TYPE_DATA_FINAL");
+ da_event_type_data = Q_EVENT_TYPE_DATA_FINAL;
+ } else {
+ da_event_type_data = Q_EVENT_TYPE_DATA_PACKET;
+ if (received_body_len > 0) {
+ body_buffer = (char*) calloc(1, received_body_len);
+ DA_LOG_VERBOSE(HTTPManager,"body_buffer[%p]msg[%p]",body_buffer,msg);
+ if (body_buffer == DA_NULL) {
+ DA_LOG_ERR(HTTPManager,"DA_ERR_FAIL_TO_MEMALLOC");
+ goto ERR;
+ }
+ memcpy(body_buffer, body_data, received_body_len);
+ }
+ }
+
+ da_queue = _pi_http_get_queue_from_session_table_entry(
+ session_table_entry);
+
+ ret = Q_make_http_data_event(da_event_type_data, &da_event);
+ if (ret != DA_RESULT_OK) {
+ DA_LOG_ERR(HTTPManager,"fail to make da_event");
+ goto ERR;
+ } else {
+ Q_set_status_code_on_http_data_event(da_event, http_status);
+ Q_set_http_body_on_http_data_event(da_event, received_body_len,
+ body_buffer);
+
+ _da_thread_mutex_lock (&(da_queue->mutex_queue));
+ b_ret = Q_push_event_without_lock(da_queue, da_event);
+ if (b_ret == DA_FALSE) {
+ DA_LOG_CRITICAL(HTTPManager,"----------------------------------------fail to push!");
+
+ pthread_mutex_t *session_mutex = NULL;
+ pthread_cond_t *session_cond = NULL;
+
+ session_mutex
+ = &(pi_session_table[session_table_entry].mutex);
+ session_cond
+ = &(pi_session_table[session_table_entry].cond);
+
+ /* MUST keep this order for these mutexes */
+ _da_thread_mutex_lock (session_mutex);
+ _da_thread_mutex_unlock (&(da_queue->mutex_queue));
+
+ if (pi_session_table[session_table_entry].is_paused
+ == DA_FALSE) {
+ DA_LOG_CRITICAL(HTTPManager,"paused!");
+ pi_session_table[session_table_entry].is_paused
+ = DA_TRUE;
+ _da_thread_cond_wait(session_cond, session_mutex);
+ } else {
+ DA_LOG_CRITICAL(HTTPManager,"NOT paused!");
+ }
+
+ _da_thread_mutex_unlock (session_mutex);
+
+ DA_LOG_CRITICAL(HTTPManager,"wake up! push again");
+ Q_push_event(da_queue, da_event);
+ } else {
+ _da_thread_mutex_unlock (&(da_queue->mutex_queue));
+ }
+
+ }
+
+ return;
+
+ERR:
+ if (DA_RESULT_OK != ret) {
+ if (DA_NULL != body_buffer) {
+ free(body_buffer);
+ }
+ }
+
+ return;
+}
+
+int _translate_error_code(int soup_error)
+{
+ DA_LOG_CRITICAL(HTTPManager, "soup error code[%d]", soup_error);
+ switch (soup_error) {
+ case SOUP_STATUS_CANT_RESOLVE:
+ case SOUP_STATUS_CANT_RESOLVE_PROXY:
+ case SOUP_STATUS_CANT_CONNECT:
+ case SOUP_STATUS_CANT_CONNECT_PROXY:
+ case SOUP_STATUS_IO_ERROR:
+ case SOUP_STATUS_MALFORMED:
+ case SOUP_STATUS_TRY_AGAIN:
+ return DA_ERR_NETWORK_FAIL;
+ case SOUP_STATUS_SSL_FAILED:
+ return DA_ERR_SSL_FAIL;
+ case SOUP_STATUS_REQUEST_TIMEOUT:
+ return DA_ERR_HTTP_TIMEOUT;
+ case SOUP_STATUS_TOO_MANY_REDIRECTS:
+ return DA_ERR_TOO_MANY_REDIECTS;
+ default:
+ return DA_ERR_NETWORK_FAIL;
+ }
+}
+
+void _pi_http_store_neterr_to_queue(SoupMessage *msg)
+{
+ da_result_t ret = DA_RESULT_OK;
+ int error_type = -1;
+ queue_t *da_queue = NULL;
+ q_event_t *da_event = NULL;
+ int session_table_entry = -1;
+
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ error_type = _translate_error_code(msg->status_code);
+
+ session_table_entry
+ = _pi_http_get_session_table_entry_from_message(msg);
+ if (session_table_entry == -1) {
+ DA_LOG_ERR(HTTPManager,"Fail to find matched session table entry..");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+
+ da_queue = _pi_http_get_queue_from_session_table_entry(
+ session_table_entry);
+
+ DA_LOG_CRITICAL(HTTPManager,"Q_EVENT_TYPE_DATA_ABORT");
+ ret = Q_make_http_data_event(Q_EVENT_TYPE_DATA_ABORT, &da_event);
+ if (ret != DA_RESULT_OK) {
+ DA_LOG_ERR(HTTPManager,"fail to make da_event");
+ goto ERR;
+ } else {
+ Q_set_error_type_on_http_data_event(da_event, error_type);
+
+ Q_push_event(da_queue, da_event);
+ }
+
+ERR:
+ return;
+}
+
+int _pi_http_get_session_table_entry_from_message(SoupMessage *msg)
+{
+
+ int out_entry = -1;
+ int i;
+
+ if (DA_NULL == msg) {
+ DA_LOG_ERR(HTTPManager,"invalid message = %p", msg);
+ return out_entry;
+ }
+
+ _da_thread_mutex_lock (&mutex_for_session_table);
+
+ for (i = 0; i < MAX_SESSION_COUNT; i++) {
+ if (pi_session_table[i].is_using == DA_TRUE) {
+ if (pi_session_table[i].msg == msg) {
+ out_entry = i;
+ break;
+ }
+ }
+ }
+
+ _da_thread_mutex_unlock (&mutex_for_session_table);
+
+ if (i == MAX_SESSION_COUNT) {
+ DA_LOG_ERR(HTTPManager,"fail to find message = %p", msg);
+ }
+
+ return out_entry;
+
+}
+
+void _pi_http_finished_cb(SoupSession *session, SoupMessage *msg, gpointer data)
+{
+ char *url = NULL;
+
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!msg) {
+ DA_LOG_ERR(HTTPManager, "Check NULL:msg");
+ return;
+ }
+
+ url = soup_uri_to_string(soup_message_get_uri(msg), DA_FALSE);
+
+ DA_SECURE_LOGI("status_code[%d], reason[%s], url[%s]",msg->status_code,msg->reason_phrase,url);
+
+ if (url) {
+ free(url);
+ url = NULL;
+ }
+
+ if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code)) {
+ if (msg->status_code == SOUP_STATUS_CANCELLED) {
+ _pi_http_store_read_data_to_queue(msg, DA_NULL, 0);
+ } else {
+ _pi_http_store_neterr_to_queue(msg);
+ }
+ } else {
+ _pi_http_store_read_data_to_queue(msg, DA_NULL, 0);
+ }
+
+}
+
+/* this callback is called in case of redirection */
+void _pi_http_restarted_cb(SoupMessage *msg, gpointer data)
+{
+ DA_LOG_FUNC_LOGD(HTTPManager);
+ /* Location URL is needed when extracting the file name from url.
+ * So, the response header should be handled by http mgr.*/
+
+ if (!msg) {
+ DA_LOG_ERR(HTTPManager, "Check NULL:msg");
+ return;
+ }
+ // If there are user id and password at url, libsoup handle it automatically.
+ if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
+ DA_LOG(HTTPManager,"Ignore:Unauthorized");
+ return;
+ }
+ _pi_http_store_read_header_to_queue(msg, NULL);
+}
+
+void _pi_http_gotheaders_cb(SoupMessage *msg, gpointer data)
+{
+ DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!msg) {
+ DA_LOG_ERR(HTTPManager, "Check NULL:msg");
+ return;
+ }
+
+ if (SOUP_STATUS_IS_REDIRECTION(msg->status_code)) {
+ DA_LOG(HTTPManager,"Redirection !!");
+ if (SOUP_STATUS_NOT_MODIFIED != msg->status_code)
+ return;
+ }
+
+ // If there are user id and password at url, libsoup handle it automatically.
+ if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
+ DA_LOG(HTTPManager,"Ignore:Unauthorized");
+ return;
+ }
+
+ soup_message_body_set_accumulate(msg->response_body, DA_FALSE);
+
+ if (!using_content_sniffing)
+ _pi_http_store_read_header_to_queue(msg, NULL);
+ else
+ DA_LOG_DEBUG(HTTPManager,"ignore because content sniffing is turned on");
+}
+
+void _pi_http_contentsniffed_cb(SoupMessage *msg, const char *sniffedType,
+ GHashTable *params, gpointer data)
+{
+ DA_LOG_FUNC_LOGD(HTTPManager);
+
+ if (!msg) {
+ DA_LOG_ERR(HTTPManager, "Check NULL:msg");
+ return;
+ }
+
+ if (SOUP_STATUS_IS_REDIRECTION(msg->status_code)) {
+ DA_LOG(HTTPManager,"Redirection !!");
+ if (SOUP_STATUS_NOT_MODIFIED != msg->status_code)
+ return;
+ }
+
+ // If there are user id and password at url, libsoup handle it automatically.
+ if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
+ DA_LOG(HTTPManager,"Ignore:Unauthorized");
+ return;
+ }
+
+ if (using_content_sniffing)
+ _pi_http_store_read_header_to_queue(msg, sniffedType);
+}
+
+void _pi_http_gotchunk_cb(SoupMessage *msg, SoupBuffer *chunk, gpointer data)
+{
+// DA_LOG_FUNC_LOGV(HTTPManager);
+
+ if (!msg) {
+ DA_LOG_ERR(HTTPManager, "Check NULL:msg");
+ return;
+ }
+
+ if (!chunk) {
+ DA_LOG_ERR(HTTPManager, "Check NULL:chunk");
+ return;
+ }
+
+ if (SOUP_STATUS_IS_REDIRECTION(msg->status_code))
+ return;
+
+ if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
+ DA_LOG(HTTPManager,"Ignore:Unauthorized");
+ return;
+ }
+
+ if (chunk->data && chunk->length > 0) {
+ _pi_http_store_read_data_to_queue(msg, chunk->data,
+ chunk->length);
+ }
+}
diff --git a/agent/download-agent-utils-dl-id-history.c b/agent/download-agent-utils-dl-id-history.c
new file mode 100755
index 0000000..c6e747d
--- /dev/null
+++ b/agent/download-agent-utils-dl-id-history.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 "download-agent-type.h"
+#include "download-agent-utils.h"
+#include "download-agent-utils-dl-id-history.h"
+
+da_result_t init_dl_id_history(dl_id_history_t *dl_id_history)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ /* Initial dl_id_history will be starting number for dl_id.
+ * dl_id will be sequentially increased from the dl_id_history,
+ * then dl_id_history will be updated. */
+ _da_thread_mutex_init(&(dl_id_history->mutex), DA_NULL);
+ _da_thread_mutex_lock(&(dl_id_history->mutex));
+ get_random_number(&(dl_id_history->starting_num));
+ dl_id_history->cur_dl_id = DA_INVALID_ID;
+ _da_thread_mutex_unlock(&(dl_id_history->mutex));
+
+ DA_LOG_VERBOSE(Default,"starting num = %d", dl_id_history->starting_num);
+ return ret;
+}
+
+da_result_t deinit_dl_id_history(dl_id_history_t *dl_id_history)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ _da_thread_mutex_lock(&(dl_id_history->mutex));
+ dl_id_history->starting_num = DA_INVALID_ID;
+ dl_id_history->cur_dl_id = DA_INVALID_ID;
+ _da_thread_mutex_unlock(&(dl_id_history->mutex));
+
+ _da_thread_mutex_destroy(&(dl_id_history->mutex));
+
+ return ret;
+}
+
+int get_available_dl_id(dl_id_history_t *dl_id_history)
+{
+ int dl_id = 0;
+
+ _da_thread_mutex_lock(&(dl_id_history->mutex));
+
+ if (dl_id_history->cur_dl_id == DA_INVALID_ID)
+ dl_id_history->cur_dl_id = dl_id_history->starting_num;
+ else if (dl_id_history->cur_dl_id > 254)
+ dl_id_history->cur_dl_id = 1;
+ else
+ dl_id_history->cur_dl_id++;
+
+ dl_id = dl_id_history->cur_dl_id;
+
+ _da_thread_mutex_unlock(&(dl_id_history->mutex));
+
+ DA_LOG_VERBOSE(Default,"dl_id = %d", dl_id);
+ return dl_id;
+}
diff --git a/agent/download-agent-utils.c b/agent/download-agent-utils.c
new file mode 100755
index 0000000..3be2257
--- /dev/null
+++ b/agent/download-agent-utils.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <sys/vfs.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <glib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "download-agent-client-mgr.h"
+#include "download-agent-debug.h"
+#include "download-agent-dl-mgr.h"
+#include "download-agent-file.h"
+#include "download-agent-http-misc.h"
+#include "download-agent-mime-util.h"
+#include "download-agent-utils.h"
+#include "download-agent-plugin-conf.h"
+#include "download-agent-dl-info-util.h"
+
+#define DA_HTTP_HEADER_CONTENT_TYPE "Content-Type"
+#define DA_HTTP_HEADER_CONTENT_LENGTH "Content-Length"
+#define DA_FILE_NUMBER_LIMIT (1024*1024)
+
+typedef struct _da_descriptor_mime_table_t {
+ char *content_type;
+ da_mime_type_id_t mime_type;
+} da_descriptor_mime_table_t;
+
+da_descriptor_mime_table_t
+ descriptor_mime_table[] = {
+ {"", DA_MIME_TYPE_NONE},
+ /* DRM1.0 */
+ {"application/vnd.oma.drm.message",
+ DA_MIME_TYPE_DRM1_MESSATE}, /* drm1.0 FL.CD*/
+ {"", DA_MIME_TYPE_END}};
+
+void get_random_number(int *out_num)
+{
+ int temp = DA_INVALID_ID;
+ unsigned int seed = (unsigned)time(0);
+
+ temp = (int)(rand_r(&seed) % 100 + 1.0);
+ *out_num = temp;
+}
+
+da_result_t get_extension_from_mime_type(char *mime_type, char **extension)
+{
+ da_result_t ret = DA_RESULT_OK;
+ char *ext = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(Default);
+ if (DA_NULL == mime_type || DA_NULL == extension) {
+ DA_LOG_ERR(Default,"received mime_type is null");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+// DA_SECURE_LOGD("input mime type = %s", mime_type);
+ if (DA_RESULT_OK != (ret = da_mime_get_ext_name(mime_type, &ext))) {
+ DA_LOG_ERR(Default,"can't find proper extension!");
+ goto ERR;
+ }
+ *extension = ext;
+// DA_SECURE_LOGD("found extension = %s", *extension);
+
+ERR:
+ return ret;
+}
+
+int read_data_from_file(char *file, char **out_buffer)
+{
+ FILE *fd;
+ unsigned long long file_size = -1;
+ char *buffer = NULL;
+ int buffer_len = 0;
+ size_t read_len = 0;
+
+ *out_buffer = NULL;
+
+ if (!file)
+ return 0;
+
+ /* open file with "rb", because fread() handles the file as binary mode */
+ fd = fopen(file, "rb");
+ if (!fd) {
+ DA_LOG_ERR(FileManager,"File open err! received file path");
+ return 0;
+ }
+
+ get_file_size(file, &file_size);
+ if (file_size <= 0) {
+ DA_LOG_ERR(FileManager,"file size is [%llu]", file_size);
+ fclose(fd);
+ return 0;
+ }
+
+ /* A guide from www.securecoding.cert.org
+ * : FIO17-C. Do not rely on an ending null character when using fread()
+ *
+ * buffer is initialized with null through calloc(), so, it is always null-terminated even if fread() failed.
+ * allocate memory one more byte to ensure null-terminated even if the file is not null-terminated.
+ */
+ buffer_len = sizeof(char) * file_size;
+ buffer = (char *)calloc(1, buffer_len + 1);
+ if (buffer) {
+ read_len = fread(buffer, sizeof(char), file_size, fd);
+ if (read_len == file_size) {
+ *out_buffer = buffer;
+ } else {
+ DA_LOG_ERR(FileManager,"File Read Not Complete read length = %d", read_len);
+ free(buffer);
+ buffer = NULL;
+ buffer_len = 0;
+ }
+ } else {
+ buffer_len = 0;
+ }
+
+ fclose(fd);
+
+ return buffer_len;
+}
+
+da_mime_type_id_t get_mime_type_id(char *content_type)
+{
+ int i = 0;
+
+ if (content_type == NULL) {
+ DA_LOG_CRITICAL(Default, "No Mime Type Id");
+ return DA_MIME_TYPE_NONE;
+ }
+
+ while(descriptor_mime_table[i].mime_type != DA_MIME_TYPE_END)
+ {
+ if (!strcmp(descriptor_mime_table[i].content_type, content_type)) {
+ break;
+ }
+ i++;
+ }
+ //DA_LOG_VERBOSE(Default, "dd mime type check: index[%d] type[%d]", i, descriptor_mime_table[i].mime_type);
+ return descriptor_mime_table[i].mime_type;
+}
+
+
+
+da_bool_t is_valid_url(const char *url, da_result_t *err_code)
+{
+ da_result_t ret = DA_RESULT_OK;
+ da_bool_t b_ret = DA_FALSE;
+
+ int wanted_str_len = 0;
+ char *wanted_str = NULL;
+ char *wanted_str_start = NULL;
+ char *wanted_str_end = NULL;
+
+ if ((DA_NULL == url) || (1 > strlen(url))) {
+ ret = DA_ERR_INVALID_URL;
+ goto ERR;
+ }
+
+ wanted_str_start = (char*)url;
+ wanted_str_end = strstr(url, "://");
+ if (!wanted_str_end) {
+ DA_LOG_ERR(Default,"No protocol on this url");
+ ret = DA_ERR_INVALID_URL;
+ goto ERR;
+ }
+
+ wanted_str_len = wanted_str_end - wanted_str_start;
+ wanted_str = (char*)calloc(1, wanted_str_len + 1);
+ if (!wanted_str) {
+ DA_LOG_ERR(Default,"DA_ERR_FAIL_TO_MEMALLOC");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ }
+ strncpy(wanted_str, wanted_str_start, wanted_str_len);
+
+ b_ret = is_supporting_protocol(wanted_str);
+ if (!b_ret) {
+ ret = DA_ERR_UNSUPPORTED_PROTOCAL;
+ goto ERR;
+ }
+
+ERR:
+ if (wanted_str) {
+ free(wanted_str);
+ wanted_str = NULL;
+ }
+
+ if (err_code)
+ *err_code = ret;
+
+ return b_ret;
+}
+
+da_result_t move_file(const char *from_path, const char *to_path)
+{
+ da_result_t ret = DA_RESULT_OK;
+
+ if (!from_path || !to_path)
+ return DA_ERR_INVALID_ARGUMENT;
+
+ if (rename(from_path, to_path) != 0) {
+ DA_LOG_CRITICAL(FileManager,"rename failed : syserr[%d]",errno);
+ if (errno == EXDEV) {
+ DA_LOG_CRITICAL(FileManager,"File system is diffrent. Try to copy a file");
+ ret = copy_file(from_path, to_path);
+ if (ret == DA_RESULT_OK) {
+ remove_file(from_path);
+ } else {
+ if (is_file_exist(to_path))
+ remove_file(to_path);
+ ret = DA_ERR_FAIL_TO_INSTALL_FILE;
+ }
+ } else {
+ ret = DA_ERR_FAIL_TO_INSTALL_FILE;
+ }
+ }
+ return ret;
+}
+
+void remove_file(const char *file_path)
+{
+ DA_LOG_FUNC_LOGD(FileManager);
+
+ if (file_path && is_file_exist(file_path)) {
+ DA_SECURE_LOGD("remove file [%s]", file_path);
+ if (unlink(file_path) < 0) {
+ DA_LOG_ERR(FileManager,"file removing failed.");
+ }
+ }
+}
diff --git a/agent/include/download-agent-basic.h b/agent/include/download-agent-basic.h
new file mode 100755
index 0000000..340a34a
--- /dev/null
+++ b/agent/include/download-agent-basic.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Basic_H
+#define _Download_Agent_Basic_H
+
+#include <string.h>
+
+#include "download-agent-type.h"
+#include "download-agent-interface.h"
+#include "download-agent-dl-mgr.h"
+
+da_result_t start_download(const char *url, int *dl_id);
+da_result_t start_download_with_extension(const char *url , int *dl_id, extension_data_t *extension_data);
+
+#endif
diff --git a/agent/include/download-agent-client-mgr.h b/agent/include/download-agent-client-mgr.h
new file mode 100755
index 0000000..f4c6234
--- /dev/null
+++ b/agent/include/download-agent-client-mgr.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Client_Mgr_H
+#define _Download_Agent_Client_Mgr_H
+
+#include <string.h>
+
+#include "download-agent-type.h"
+#include "download-agent-interface.h"
+
+#include "download-agent-pthread.h"
+
+typedef enum {
+ Q_CLIENT_NOTI_TYPE_STARTED_INFO = 0,
+ Q_CLIENT_NOTI_TYPE_PROGRESS_INFO,
+ Q_CLIENT_NOTI_TYPE_PAUSED_INFO,
+ Q_CLIENT_NOTI_TYPE_FINISHED_INFO,
+ Q_CLIENT_NOTI_TYPE_TERMINATE,
+} client_noti_type;
+
+typedef struct _client_noti_t client_noti_t;
+struct _client_noti_t {
+ int slot_id;
+ void *user_data;
+ client_noti_type noti_type;
+ union _client_type {
+ user_download_info_t update_dl_info;
+ user_progress_info_t update_progress_info;
+ user_paused_info_t paused_info;
+ user_finished_info_t finished_info;
+ } type;
+
+ client_noti_t *next;
+};
+
+typedef struct _client_queue_t {
+ da_bool_t having_data;
+ client_noti_t *client_q_head;
+ pthread_mutex_t mutex_client_queue;
+ pthread_cond_t cond_client_queue;
+} client_queue_t;
+
+typedef struct _client_app_info_t {
+ da_client_cb_t client_callback;
+ char *client_user_agent;
+} client_app_info_t;
+
+typedef struct _client_app_mgr_t {
+ da_bool_t is_init;
+ client_queue_t client_queue;
+ client_app_info_t client_app_info;
+ pthread_t thread_id;
+ da_bool_t is_thread_init;
+ pthread_mutex_t mutex_client_mgr;
+} client_app_mgr_t;
+
+da_result_t init_client_app_mgr(void);
+da_bool_t is_client_app_mgr_init(void);
+
+da_result_t reg_client_app(da_client_cb_t *da_client_callback);
+da_result_t dereg_client_app(void);
+
+da_result_t send_client_paused_info (int slot_id);
+da_result_t send_client_update_dl_info (int slot_id, int dl_id,
+ char *file_type, unsigned long int file_size, char *tmp_saved_path,
+ char *pure_file_name, char *etag, char *extension);
+da_result_t send_client_update_progress_info (int slot_id, int dl_id,
+ unsigned long int received_size);
+da_result_t send_client_finished_info (int slot_id, int dl_id,
+ char *saved_path, char *etag, int error, int http_status);
+
+char *get_client_user_agent_string(void);
+
+void push_client_noti(client_noti_t *client_noti);
+
+#endif
diff --git a/agent/include/download-agent-debug.h b/agent/include/download-agent-debug.h
new file mode 100755
index 0000000..24ac67e
--- /dev/null
+++ b/agent/include/download-agent-debug.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Debug_H
+#define _Download_Agent_Debug_H
+
+#include "download-agent-type.h"
+
+#define DA_DEBUG_ENV_KEY "DOWNLOAD_AGENT_DEBUG"
+#define DA_DEBUG_CONFIG_FILE_PATH "/tmp/.download_agent.conf"
+
+#define IS_LOG_ON(channel) (DALogBitMap & (0x1<<(channel)))
+
+typedef enum {
+ Soup,
+ HTTPManager,
+ FileManager,
+ DRMManager,
+ DownloadManager,
+ ClientNoti,
+ HTTPMessageHandler,
+ Encoding,
+ QueueManager,
+ Parsing,
+ Thread,
+ Default,
+ DA_LOG_CHANNEL_MAX
+} da_log_channel;
+
+extern int DALogBitMap;
+
+da_result_t init_log_mgr(void);
+
+#ifdef NODEBUG
+ #define DA_LOG(channel, format, ...) ((void)0)
+ #define DA_LOG_CRITICAL(channel, format, ...) ((void)0)
+ #define DA_LOG_VERBOSE(channel, format, ...) ((void)0)
+ #define DA_LOG_ERR(channel, format, ...) ((void)0)
+ #define DA_LOG_FUNC_LOGD(channel, ...) ((void)0)
+ #define DA_LOG_FUNC_LOGV(channel, ...) ((void)0)
+ #define DA_SECURE_LOGD(format, ...) ((void)0)
+ #define DA_SECURE_LOGI(format, ...) ((void)0)
+ #define DA_SECURE_LOGE(format, ...) ((void)0)
+
+#else /* NODEBUG */
+#include <stdio.h>
+#include <stdarg.h>
+#include <pthread.h>
+
+#ifdef DA_DEBUG_USING_DLOG
+ #include <dlog.h>
+ #ifdef LOG_TAG
+ #undef LOG_TAG
+ #endif /* LOG_TAG */
+ #define LOG_TAG "DOWNLOAD_AGENT"
+
+ #define DA_LOG(channel, format, ...) LOGI_IF(IS_LOG_ON(channel), format, ##__VA_ARGS__)
+ #define DA_LOG_DEBUG(channel, format, ...) LOGD_IF(IS_LOG_ON(channel), format, ##__VA_ARGS__)
+ #define DA_LOG_CRITICAL(channel, format, ...) LOGI_IF(IS_LOG_ON(channel), format, ##__VA_ARGS__)
+ #define DA_LOG_VERBOSE(channel, format, ...) ((void)0)//LOGD_IF(IS_LOG_ON(channel), format, ##__VA_ARGS__)
+ #define DA_LOG_ERR(channel, format, ...) LOGE_IF(IS_LOG_ON(channel), "ERR! "format, ##__VA_ARGS__)
+ #define DA_LOG_FUNC_LOGD(channel, ...) LOGD_IF(IS_LOG_ON(channel), "starting...")
+ #define DA_LOG_FUNC_LOGV(channel, ...) ((void)0)//LOGD_IF(IS_LOG_ON(channel), "starting...")
+ #define DA_SECURE_LOGD(format, ...) SECURE_LOGD(format, ##__VA_ARGS__)
+ #define DA_SECURE_LOGI(format, ...) SECURE_LOGI(format, ##__VA_ARGS__)
+ #define DA_SECURE_LOGE(format, ...) SECURE_LOGE(format, ##__VA_ARGS__)
+#else /* DA_DEBUG_USING_DLOG */
+ #include <unistd.h>
+ #include <syscall.h>
+
+ #define DA_LOG(channel, format, ...) do {\
+ IS_LOG_ON(channel) \
+ ? fprintf(stderr, "[DA][%u][%s(): %d] "format"\n",(unsigned int)syscall(__NR_gettid), __FUNCTION__,__LINE__, ##__VA_ARGS__) \
+ : ((void)0);\
+ }while(0)
+ #define DA_LOG_ERR(channel, format, ...) do {\
+ IS_LOG_ON(channel) \
+ ? fprintf(stderr, "[DA][%u][ERR][%s(): %d]\n",(unsigned int)syscall(__NR_gettid), __FUNCTION__,__LINE__, ##__VA_ARGS__) \
+ : ((void)0); \
+ }while(0)
+ #define DA_LOG_FUNC_LOGD(channel, ...) do {\
+ IS_LOG_ON(channel) \
+ ? fprintf(stderr, "[DA][%u][%s(): %d] starting\n",(unsigned int)syscall(__NR_gettid), __FUNCTION__,__LINE__) \
+ : ((void)0); \
+ }while(0)
+ #define DA_LOG_CRITICAL DA_LOG
+ #define DA_LOG_VERBOSE DA_LOG
+ #define DA_LOG_FUNC_LOGV ((void)0)
+ #define DA_SECURE_LOGD(format, ...) ((void)0)
+ #define DA_SECURE_LOGI(format, ...) ((void)0)
+ #define DA_SECURE_LOGE(format, ...) ((void)0)
+#endif /* DA_DEBUG_USING_DLOG */
+#endif /* NDEBUG */
+#endif /* _Download_Agent_Debug_H */
diff --git a/agent/include/download-agent-defs.h b/agent/include/download-agent-defs.h
new file mode 100755
index 0000000..b69690a
--- /dev/null
+++ b/agent/include/download-agent-defs.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Defs_H
+#define _Download_Agent_Defs_H
+
+#ifndef DEPRECATED
+#define DEPRECATED __attribute__((deprecated))
+#endif
+
+/**
+ * Max count to download files simultaneously. \n
+ * Main reason for this restriction is because of Network bandwidth.
+ */
+#define DA_MAX_DOWNLOAD_REQ_AT_ONCE 50
+
+#define DA_RESULT_OK 0
+
+#define DA_TRUE 1
+#define DA_FALSE 0
+#define DA_NULL (void *)0
+#define DA_INVALID_ID -1
+
+#define DA_RESULT_USER_CANCELED -10
+
+// InputError Input error (-100 ~ -199)
+// Client passed wrong parameter
+#define DA_ERR_INVALID_ARGUMENT -100
+#define DA_ERR_INVALID_DL_REQ_ID -101
+#define DA_ERR_INVALID_URL -103
+#define DA_ERR_INVALID_INSTALL_PATH -104
+#define DA_ERR_INVALID_MIME_TYPE -105
+
+// Client passed correct parameter, but Download Agent rejects the request because of internal policy.
+#define DA_ERR_ALREADY_CANCELED -160
+#define DA_ERR_ALREADY_SUSPENDED -161
+#define DA_ERR_ALREADY_RESUMED -162
+#define DA_ERR_CANNOT_SUSPEND -170
+#define DA_ERR_CANNOT_RESUME -171
+#define DA_ERR_INVALID_STATE -190
+#define DA_ERR_ALREADY_MAX_DOWNLOAD -191
+#define DA_ERR_UNSUPPORTED_PROTOCAL -192
+
+// System error (-200 ~ -299)
+#define DA_ERR_FAIL_TO_MEMALLOC -200
+#define DA_ERR_FAIL_TO_CREATE_THREAD -210
+#define DA_ERR_FAIL_TO_OBTAIN_MUTEX -220
+#define DA_ERR_FAIL_TO_ACCESS_FILE -230
+#define DA_ERR_DISK_FULL -240
+
+// Platform error (-300 ~ -399)
+#define DA_ERR_FAIL_TO_GET_CONF_VALUE -300
+#define DA_ERR_FAIL_TO_ACCESS_STORAGE -310
+#define DA_ERR_DLOPEN_FAIL -330
+
+// Network error (-400 ~ -499)
+#define DA_ERR_NETWORK_FAIL -400
+#define DA_ERR_UNREACHABLE_SERVER -410
+#define DA_ERR_HTTP_TIMEOUT -420
+#define DA_ERR_SSL_FAIL -430
+#define DA_ERR_TOO_MANY_REDIECTS -440
+
+// HTTP error - not conforming with HTTP spec (-500 ~ -599)
+#define DA_ERR_MISMATCH_CONTENT_TYPE -500
+#define DA_ERR_MISMATCH_CONTENT_SIZE -501
+#define DA_ERR_SERVER_RESPOND_BUT_SEND_NO_CONTENT -502
+
+// DRM error - not conforming with DRM spec (-700 ~ -799)
+#define DA_ERR_DRM_FAIL -700
+#define DA_ERR_DRM_FILE_FAIL -710
+
+// install error (-800 ~ -899)
+#define DA_ERR_FAIL_TO_INSTALL_FILE -800
+
+#endif
+
diff --git a/agent/include/download-agent-dl-info-util.h b/agent/include/download-agent-dl-info-util.h
new file mode 100755
index 0000000..d6e20a8
--- /dev/null
+++ b/agent/include/download-agent-dl-info-util.h
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Dl_Info_Util_H
+#define _Download_Agent_Dl_Info_Util_H
+
+#include "download-agent-type.h"
+#include "download-agent-http-queue.h"
+#include "download-agent-utils-dl-id-history.h"
+
+#define DA_MAX_DOWNLOAD_ID DA_MAX_DOWNLOAD_REQ_AT_ONCE
+#define DA_MAX_TYPE_COUNT 10
+
+#define DOWNLOAD_NOTIFY_LIMIT (1024*32) //bytes
+extern pthread_mutex_t mutex_download_state[];
+
+typedef enum {
+ DOWNLOAD_STATE_IDLE = 0,
+ DOWNLOAD_STATE_NEW_DOWNLOAD = 10, /* stage */
+ DOWNLOAD_STATE_FINISH = 50, /* stage */
+ DOWNLOAD_STATE_PAUSED = 60, /* http */
+ DOWNLOAD_STATE_CANCELED = 70, /* http */
+ DOWNLOAD_STATE_ABORTED = 80 /* satge */
+} download_state_t;
+
+typedef enum {
+ HTTP_STATE_READY_TO_DOWNLOAD = 0,
+ HTTP_STATE_REDIRECTED = 1,
+ HTTP_STATE_DOWNLOAD_REQUESTED = 2,
+ HTTP_STATE_DOWNLOAD_STARTED = 3,
+ HTTP_STATE_DOWNLOADING = 4,
+ HTTP_STATE_DOWNLOAD_FINISH = 5,
+ HTTP_STATE_REQUEST_CANCEL = 6,
+ HTTP_STATE_REQUEST_PAUSE = 7,
+ HTTP_STATE_REQUEST_RESUME = 8,
+ HTTP_STATE_CANCELED = 9,
+ HTTP_STATE_PAUSED = 10,
+ HTTP_STATE_RESUMED = 11,
+ HTTP_STATE_ABORTED = 12,
+} http_state_t;
+
+typedef struct _client_input_basic_t {
+ char *req_url;
+ char **user_request_header;
+ int user_request_header_count;
+} client_input_basic_t;
+
+typedef struct _client_input_t {
+ void *user_data;
+ char *install_path;
+ char *file_name;
+ char *etag;
+ char *temp_file_path;
+ char *pkg_name;
+ client_input_basic_t client_input_basic;
+} client_input_t;
+
+typedef struct _download_thread_input {
+ int slot_id;
+ client_input_t *client_input;
+} download_thread_input;
+
+typedef struct _source_info_basic_t {
+ int dl_id;
+ char *url;
+ char **user_request_header;
+ int user_request_header_count;
+} source_info_basic_t;
+
+typedef struct _source_info_t {
+ union _source_info_type {
+ source_info_basic_t *source_info_basic;
+ } source_info_type;
+} source_info_t;
+
+#define GET_SOURCE_TYPE(SOURCE) ((SOURCE)->source_type)
+#define GET_SOURCE_BASIC(SOURCE) ((SOURCE)->source_info_type.source_info_basic)
+#define GET_SOURCE_BASIC_URL(SOURCE) (GET_SOURCE_BASIC(SOURCE)->url)
+
+typedef struct _req_dl_info {
+ http_info_t http_info;
+
+ /* This is just pointer assignment from stage source info. */
+ char *destination_url;
+ /* The location url is assigned here in case of redirection.
+ * At this time, the pointer should be freed. */
+ char *location_url;
+ char **user_request_header;
+ int user_request_header_count;
+ char *user_request_etag;
+ char *user_request_temp_file_path;
+
+ http_state_t http_state;
+ pthread_mutex_t mutex_http_state;
+
+ da_result_t result;
+ /*************** will be depreciated ***********************/
+ /* ToDo : previous http_info should be saved in case of pause */
+ char *content_type_from_header; /* calloced in set hdr fiels on download info */
+ unsigned long long content_len_from_header;
+ char *etag_from_header;
+
+ unsigned long int downloaded_data_size;
+
+ int invloved_transaction_id;
+} req_dl_info;
+
+#define GET_REQUEST_HTTP_RESULT(REQUEST) (REQUEST->result)
+#define GET_REQUEST_HTTP_TRANS_ID(REQUEST) (REQUEST->invloved_transaction_id)
+#define GET_REQUEST_HTTP_REQ_URL(REQUEST) (REQUEST->destination_url)
+#define GET_REQUEST_HTTP_REQ_LOCATION(REQUEST) (REQUEST->location_url)
+#define GET_REQUEST_HTTP_USER_REQUEST_HEADER(REQUEST) (REQUEST->user_request_header)
+#define GET_REQUEST_HTTP_USER_REQUEST_HEADER_COUNT(REQUEST) (REQUEST->user_request_header_count)
+#define GET_REQUEST_HTTP_USER_REQUEST_ETAG(REQUEST) (REQUEST->user_request_etag)
+#define GET_REQUEST_HTTP_USER_REQUEST_TEMP_FILE_PATH(REQUEST) (REQUEST->user_request_temp_file_path)
+#define GET_REQUEST_HTTP_HDR_ETAG(REQUEST) (REQUEST->etag_from_header)
+#define GET_REQUEST_HTTP_HDR_CONT_TYPE(REQUEST) (REQUEST->content_type_from_header)
+#define GET_REQUEST_HTTP_HDR_CONT_LEN(REQUEST) (REQUEST->content_len_from_header)
+#define GET_REQUEST_HTTP_CONTENT_OFFSET(REQUEST)(REQUEST->downloaded_data_size)
+#define GET_REQUEST_HTTP_MUTEX_HTTP_STATE(STAGE) (GET_STAGE_TRANSACTION_INFO(STAGE)->mutex_http_state)
+#define GET_HTTP_STATE_ON_STAGE(STAGE) (GET_STAGE_TRANSACTION_INFO(STAGE)->http_state)
+#define CHANGE_HTTP_STATE(STATE,STAGE) {\
+ _da_thread_mutex_lock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(STAGE)));\
+ GET_HTTP_STATE_ON_STAGE(STAGE) = STATE;\
+ DA_LOG_DEBUG(Default, "Changed http_state to - [%d] ", GET_HTTP_STATE_ON_STAGE(STAGE));\
+ _da_thread_mutex_unlock(&(GET_REQUEST_HTTP_MUTEX_HTTP_STATE(STAGE)));\
+}
+
+typedef struct _file_info {
+ void *file_handle;
+ char *pure_file_name;
+ char *extension;
+ char *file_name_final; /* malloced in set_file_path_for_final_saving */
+ char *content_type; /* malloced in make file info. */
+ char *add_to_buffer;
+ unsigned int file_size; /* http header's Content-Length has higher priority than DD's <size> */
+ unsigned int total_bytes_written_to_file; /* current written file size */
+ unsigned int bytes_written_to_file;
+ unsigned int current_buffer_len;
+} file_info;
+
+#define GET_CONTENT_STORE_PURE_FILE_NAME(FILE_CNTXT) (FILE_CNTXT)->pure_file_name
+#define GET_CONTENT_STORE_EXTENSION(FILE_CNTXT) (FILE_CNTXT)->extension
+#define GET_CONTENT_STORE_ACTUAL_FILE_NAME(FILE_CNTXT) (FILE_CNTXT)->file_name_final
+#define GET_CONTENT_STORE_FILE_HANDLE(FILE_CNTXT) (FILE_CNTXT)->file_handle
+#define GET_CONTENT_STORE_FILE_SIZE(FILE_CNTXT) (FILE_CNTXT)->file_size
+#define GET_CONTENT_STORE_CURRENT_FILE_SIZE(FILE_CNTXT) (FILE_CNTXT)->total_bytes_written_to_file
+#define IS_CONTENT_STORE_FILE_BYTES_WRITTEN_TO_FILE(FILE_CNTXT) (FILE_CNTXT)->bytes_written_to_file
+#define GET_CONTENT_STORE_FILE_BUFFER(FILE_CNTXT) (FILE_CNTXT)->add_to_buffer
+#define GET_CONTENT_STORE_FILE_BUFF_LEN(FILE_CNTXT) ((FILE_CNTXT)->current_buffer_len)
+#define GET_CONTENT_STORE_CONTENT_TYPE(FILE_CNTXT) (FILE_CNTXT)->content_type
+
+typedef struct _stage_info {
+ int dl_id;
+ int thread_id;
+ source_info_t dl_request;
+ req_dl_info dl_tansaction_context;
+ file_info dl_content_storage;
+ struct _stage_info *next_stage_info;
+} stage_info;
+
+#define GET_STAGE_DL_ID(STAGE) ((STAGE)->dl_id)
+#define GET_STAGE_THREAD_ID(STAGE) ((STAGE)->thread_id)
+#define GET_STAGE_SOURCE_INFO(STAGE) (&((STAGE)->dl_request))
+#define GET_STAGE_TRANSACTION_INFO(STAGE) (&((STAGE)->dl_tansaction_context))
+#define GET_STAGE_CONTENT_STORE_INFO(STAGE) (&((STAGE)->dl_content_storage))
+#define GET_STAGE_INSTALLATION_INFO(STAGE) (&((STAGE)->post_dl_context))
+
+typedef struct {
+ da_bool_t is_using;
+ int slot_id;
+ int dl_id;
+ pthread_t active_dl_thread_id;
+ download_state_t state;
+ stage_info *download_stage_data;
+ queue_t queue;
+ int http_status;
+ da_bool_t enable_pause_update;
+ // FIXME have client_input itself, not to have each of them
+ char *user_install_path;
+ char *user_file_name;
+ char *user_etag;
+ char *user_temp_file_path;
+ void *user_data;
+} dl_info_t;
+
+#define GET_DL_THREAD_ID(ID) (download_mgr.dl_info[ID].active_dl_thread_id)
+#define GET_DL_STATE_ON_ID(ID) (download_mgr.dl_info[ID].state)
+#define GET_DL_STATE_ON_STAGE(STAGE) (GET_DL_STATE_ON_ID(GET_STAGE_DL_ID(STAGE)))
+#define GET_DL_CURRENT_STAGE(ID) (download_mgr.dl_info[ID].download_stage_data)
+#define GET_DL_ID(ID) (download_mgr.dl_info[ID].dl_id)
+#define GET_DL_QUEUE(ID) &(download_mgr.dl_info[ID].queue)
+#define GET_DL_ENABLE_PAUSE_UPDATE(ID) (download_mgr.dl_info[ID].enable_pause_update)
+#define GET_DL_USER_INSTALL_PATH(ID) (download_mgr.dl_info[ID].user_install_path)
+#define GET_DL_USER_FILE_NAME(ID) (download_mgr.dl_info[ID].user_file_name)
+#define GET_DL_USER_ETAG(ID) (download_mgr.dl_info[ID].user_etag)
+#define GET_DL_USER_TEMP_FILE_PATH(ID) (download_mgr.dl_info[ID].user_temp_file_path)
+#define GET_DL_USER_DATA(ID) (download_mgr.dl_info[ID].user_data)
+#define IS_THIS_DL_ID_USING(ID) (download_mgr.dl_info[ID].is_using)
+
+#define CHANGE_DOWNLOAD_STATE(STATE,STAGE) {\
+ _da_thread_mutex_lock (&mutex_download_state[GET_STAGE_DL_ID(STAGE)]);\
+ GET_DL_STATE_ON_STAGE(STAGE) = STATE;\
+ DA_LOG_DEBUG(Default, "Changed download_state to - [%d] ", GET_DL_STATE_ON_STAGE(STAGE));\
+ _da_thread_mutex_unlock (&mutex_download_state[GET_STAGE_DL_ID(STAGE)]);\
+ }
+
+typedef struct _download_mgr_t {
+ da_bool_t is_init;
+ dl_info_t dl_info[DA_MAX_DOWNLOAD_ID];
+ dl_id_history_t dl_id_history;
+ /* FIXME: This is temporary solution to prevent crash on following case;
+ * 1) OMA download(that is, DA's libsoup is using) is on progressing on Browser
+ * 2) User push END hard key
+ * 3) da_deinit() is called. - on UI thread
+ * 4) cancel_download(all) is called.
+ * 5) plugin-libsoup.c calls soup_session_cancel_message().
+ * 6) da_deinit() is finished and process is over.
+ * 7) soup's callback for soup_session_cancel_message() is trying to be called - on UI thread
+ * 8) Browser crashed because the callback address is no longer exist.
+ *
+ * Here is a temporary solution;
+ * If cancel is from da_deinit(), plugin-libsoup.c will not call soup_session_cancel_message().
+ * So, append following variable to recognize this.
+ **/
+ //da_bool_t is_progressing_deinit;
+} download_mgr_t;
+
+extern download_mgr_t download_mgr;
+
+da_result_t init_download_mgr();
+da_result_t deinit_download_mgr(void);
+void init_download_info(int slot_id);
+void destroy_download_info(int slot_id);
+void *Add_new_download_stage(int slot_id);
+void remove_download_stage(int slot_id, stage_info *in_stage);
+void empty_stage_info(stage_info *in_stage);
+void clean_up_client_input_info(client_input_t *client_input);
+da_result_t get_available_slot_id(int *available_id);
+da_result_t get_slot_id_for_dl_id(int dl_id , int* slot_id);
+da_bool_t is_valid_slot_id(int slot_id);
+void store_http_status(int dl_id, int status);
+int get_http_status(int dl_id);
+#endif /* _Download_Agent_Dl_Info_Util_H */
diff --git a/agent/include/download-agent-dl-mgr.h b/agent/include/download-agent-dl-mgr.h
new file mode 100755
index 0000000..b273fd8
--- /dev/null
+++ b/agent/include/download-agent-dl-mgr.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Dl_Mgr_H
+#define _Download_Agent_Dl_Mgr_H
+
+#include "download-agent-type.h"
+#include "download-agent-dl-info-util.h"
+
+da_result_t cancel_download(int dl_id);
+da_result_t suspend_download(int dl_id, da_bool_t is_enable_cb);
+da_result_t resume_download (int dl_id);
+
+da_result_t requesting_download(stage_info *stage);
+da_result_t handle_after_download(stage_info *stage);
+da_result_t send_user_noti_and_finish_download_flow(
+ int slot_id, char *installed_path, char *etag);
+
+da_bool_t is_valid_download_id(int dl_id);
+#endif
diff --git a/agent/include/download-agent-encoding.h b/agent/include/download-agent-encoding.h
new file mode 100755
index 0000000..c5c7fe5
--- /dev/null
+++ b/agent/include/download-agent-encoding.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Encoding_H
+#define _Download_Agent_Encoding_H
+
+#include "download-agent-type.h"
+
+da_bool_t is_base64_encoded_word(const char *in_str);
+da_result_t decode_base64_encoded_str(const char *in_encoded_str,
+ char **out_decoded_ascii_str);
+void decode_url_encoded_str(const char *in_encoded_str, char **out_str);
+
+#endif // _Download_Agent_Encoding_H
diff --git a/agent/include/download-agent-file.h b/agent/include/download-agent-file.h
new file mode 100755
index 0000000..e9ff05f
--- /dev/null
+++ b/agent/include/download-agent-file.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_File_H
+#define _Download_Agent_File_H
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "download-agent-type.h"
+#include "download-agent-dl-mgr.h"
+
+da_bool_t is_file_exist(const char *file_path);
+da_bool_t is_dir_exist(const char *dir_path);
+
+void get_file_size(char *file_path, unsigned long long *out_file_size);
+
+da_result_t clean_files_from_dir(char *dir_path);
+da_result_t file_write_ongoing(stage_info *stage, char *body, int body_len);
+da_result_t file_write_complete(stage_info *stage);
+da_result_t start_file_writing(stage_info *stage);
+da_result_t start_file_writing_append(stage_info *stage);
+da_result_t start_file_writing_append_with_new_download(stage_info *stage);
+
+da_result_t get_mime_type(stage_info *stage, char **out_mime_type);
+da_result_t discard_download(stage_info *stage) ;
+void clean_paused_file(stage_info *stage);
+da_result_t replace_content_file_in_stage(stage_info *stage, const char *dest_dd_file_path);
+char *get_full_path_avoided_duplication(char *in_dir, char *in_candidate_file_name, char *in_extension);
+
+da_result_t copy_file(const char *src, const char *dest);
+
+#endif
diff --git a/agent/include/download-agent-http-mgr.h b/agent/include/download-agent-http-mgr.h
new file mode 100755
index 0000000..6653af0
--- /dev/null
+++ b/agent/include/download-agent-http-mgr.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Http_Mgr_H
+#define _Download_Agent_Http_Mgr_H
+
+#include <string.h>
+
+#include "download-agent-type.h"
+#include "download-agent-dl-mgr.h"
+#include "download-agent-http-queue.h"
+
+#define DA_MAX_SESSION_INFO DA_MAX_DOWNLOAD_ID
+#define DA_MAX_TRANSACTION_INFO 10
+#define DA_MAX_TRANSACTION_MUTEX DA_MAX_SESSION_INFO*DA_MAX_TRANSACTION_INFO
+
+typedef struct _http_mgr_t
+{
+ da_bool_t is_init;
+ da_bool_t is_http_init;
+}http_mgr_t;
+
+extern http_mgr_t http_mgr;
+
+da_result_t init_http_mgr(void);
+void deinit_http_mgr(void);
+da_result_t make_req_dl_info_http(stage_info *stage, req_dl_info *out_info);
+da_result_t request_http_download(stage_info *stage);
+da_result_t request_to_cancel_http_download(stage_info *stage);
+da_result_t request_to_abort_http_download(stage_info *stage);
+da_result_t request_to_suspend_http_download(stage_info *stage);
+da_result_t request_to_resume_http_download(stage_info *stage);
+
+#endif
diff --git a/agent/include/download-agent-http-misc.h b/agent/include/download-agent-http-misc.h
new file mode 100755
index 0000000..3bf137b
--- /dev/null
+++ b/agent/include/download-agent-http-misc.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Http_Misc_H
+#define _Download_Agent_Http_Misc_H
+
+#include <string.h>
+
+#include "download-agent-type.h"
+
+#define SCHEME_HTTP "http://"
+#define SCHEME_HTTPS "https://"
+#define SCHEME_CID "cid:"
+
+#define METHOD_GET "GET"
+#define METHOD_POST "POST"
+#define METHOD_HEAD "HEAD"
+
+#define HTTP_TAG_UAGENT "User-Agent: "
+#define HTTP_TAG_HOST "Host: "
+#define HTTP_TAG_UAPROF "X-Wap-Profile: "
+#define HTTP_TAG_CONTENT_LENGTH "Content-Length: "
+#define HTTP_TAG_CONTENT_TYPE "Content-Type: "
+#define HTTP_TAG_IF_MATCH "If-Match: "
+#define HTTP_TAG_RANGE "Range: "
+#define HTTP_TAG_IF_RANGE "If-Range: "
+
+#define END_OF_FIELD "\r\n"
+
+char *get_user_agent();
+
+da_bool_t is_supporting_protocol(const char *protocol);
+
+#endif
diff --git a/agent/include/download-agent-http-msg-handler.h b/agent/include/download-agent-http-msg-handler.h
new file mode 100755
index 0000000..29d0ae4
--- /dev/null
+++ b/agent/include/download-agent-http-msg-handler.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Http_Msg_Handler_H
+#define _Download_Agent_Http_Msg_Handler_H
+
+#include "download-agent-type.h"
+
+#define HTTP_FIELD_UAGENT "User-Agent"
+#define HTTP_FIELD_HOST "Host"
+#define HTTP_FIELD_UAPROF "X-Wap-Profile"
+#define HTTP_FIELD_CONTENT_LENGTH "Content-Length"
+#define HTTP_FIELD_CONTENT_TYPE "Content-Type"
+#define HTTP_FIELD_IF_MATCH "If-Match"
+#define HTTP_FIELD_RANGE "Range"
+#define HTTP_FIELD_IF_RANGE "If-Range"
+#define HTTP_FIELD_ACCEPT_LANGUAGE "Accept-Language"
+#define HTTP_FIELD_ACCEPT_CHARSET "Accept-Charset"
+
+typedef struct _http_header_options_t http_header_options_t;
+struct _http_header_options_t{
+ char *field;
+ char *value;
+
+ http_header_options_t *next;
+};
+
+typedef struct _http_header_t http_header_t;
+struct _http_header_t{
+ char *field;
+ char *value;
+ http_header_options_t *options;
+
+ char *raw_value; // raw string including options
+
+ http_header_t *next;
+};
+
+typedef struct{
+ char *http_method;
+ char *url;
+ http_header_t *head;
+ char *http_body;
+}http_msg_request_t;
+
+
+typedef struct{
+ int status_code;
+ http_header_t *head;
+}http_msg_response_t;
+
+typedef http_header_t *http_msg_iter_t;
+
+
+typedef struct{
+ http_msg_request_t *http_msg_request;
+ http_msg_response_t *http_msg_response;
+}http_info_t;
+
+
+da_result_t http_msg_request_create(http_msg_request_t **http_msg_request);
+void http_msg_request_destroy(http_msg_request_t **http_msg_request);
+
+da_result_t http_msg_request_set_method(http_msg_request_t *http_msg_request, const char *method);
+da_result_t http_msg_request_get_method(http_msg_request_t *http_msg_request, const char **method);
+
+da_result_t http_msg_request_set_url(http_msg_request_t *http_msg_request, const char *url);
+da_result_t http_msg_request_get_url(http_msg_request_t *http_msg_request, const char **url);
+
+da_result_t http_msg_request_set_body(http_msg_request_t *http_msg_request, const char *body);
+da_result_t http_msg_request_get_body(http_msg_request_t *http_msg_request, const char **body);
+
+da_result_t http_msg_request_add_field(http_msg_request_t *http_msg_request, const char *field, const char *value);
+
+
+da_result_t http_msg_response_create(http_msg_response_t **http_msg_response);
+void http_msg_response_destroy(http_msg_response_t **http_msg_response);
+
+da_result_t http_msg_response_set_status_code(http_msg_response_t *http_msg_response, int status_code);
+da_result_t http_msg_response_get_status_code(http_msg_response_t *http_msg_response, int *status_code);
+
+da_result_t http_msg_response_add_field(http_msg_response_t *http_msg_response, const char *field, const char *value);
+
+/* Caution! Caller must free memory for every "char** out_xxx" for followings */
+da_bool_t http_msg_response_get_content_type(http_msg_response_t *http_msg_response, char **out_type);
+void http_msg_response_set_content_type(http_msg_response_t *http_msg_response, const char *in_type);
+
+da_bool_t http_msg_response_get_content_length(http_msg_response_t *http_msg_response, unsigned long long *out_length);
+da_bool_t http_msg_response_get_content_disposition(http_msg_response_t *http_msg_response, char **out_disposition, char **out_file_name);
+da_bool_t http_msg_response_get_ETag(http_msg_response_t *http_msg_response, char **out_value);
+da_bool_t http_msg_response_get_date(http_msg_response_t *http_msg_response, char **out_value);
+da_bool_t http_msg_response_get_location(http_msg_response_t *http_msg_response, char **out_value);
+// should be refactored later
+da_result_t http_msg_response_get_boundary(http_msg_response_t *http_msg_response, char **out_val);
+
+
+da_result_t http_msg_request_get_iter(http_msg_request_t *http_msg_request, http_msg_iter_t *http_msg_iter);
+da_result_t http_msg_response_get_iter(http_msg_response_t *http_msg_response, http_msg_iter_t *http_msg_iter);
+
+// should remove later
+da_bool_t http_msg_get_field_with_iter(http_msg_iter_t *http_msg_iter, char **field, char **value);
+da_bool_t http_msg_get_header_with_iter(http_msg_iter_t *http_msg_iter, char **out_field, http_header_t **out_header);
+
+char *get_http_response_header_raw(http_msg_response_t *http_msg_response);
+
+da_bool_t extract_attribute_from_header(char *szHeadStr, const char *szFindStr, char **ppRtnValue);
+#endif // _Download_Agent_Http_Msg_Handler_H
diff --git a/agent/include/download-agent-http-queue.h b/agent/include/download-agent-http-queue.h
new file mode 100755
index 0000000..9973698
--- /dev/null
+++ b/agent/include/download-agent-http-queue.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Http_Queue_H
+#define _Download_Agent_Http_Queue_H
+
+
+#include "download-agent-type.h"
+#include "download-agent-http-msg-handler.h"
+
+#include <pthread.h>
+#include <stdlib.h>
+
+#define MAX_QUEUE_SIZE 1024*64
+
+typedef enum
+{
+ Q_EVENT_TYPE_DATA_HTTP,
+ Q_EVENT_TYPE_DATA_DRM,
+ Q_EVENT_TYPE_CONTROL,
+}q_event_type;
+
+typedef enum
+{
+ Q_EVENT_TYPE_CONTROL_NONE = 0,
+ Q_EVENT_TYPE_CONTROL_CANCEL,
+ Q_EVENT_TYPE_CONTROL_SUSPEND,
+ Q_EVENT_TYPE_CONTROL_RESUME,
+ Q_EVENT_TYPE_CONTROL_NET_DISCONNECTED,
+ Q_EVENT_TYPE_CONTROL_ABORT,
+// [090205][jungki]not used yet.
+// Q_EVENT_TYPE_CONTROL_USER_CONFIRM_RESULT,
+// Q_EVENT_TYPE_CONTROL_INSTALL_RESULT,
+}q_event_type_control;
+
+typedef enum
+{
+ Q_EVENT_TYPE_DATA_PACKET,
+ Q_EVENT_TYPE_DATA_FINAL,
+ Q_EVENT_TYPE_DATA_ABORT,
+}q_event_type_data;
+
+typedef struct _q_event_data_http_t
+{
+ q_event_type_data data_type;
+
+ int status_code;
+
+ http_msg_response_t* http_response_msg;
+
+ int body_len;
+ char *body_data;
+
+ da_result_t error_type;
+}q_event_data_http_t;
+
+typedef struct _q_event_control_t
+{
+ q_event_type_control control_type;
+}q_event_control_t;
+
+typedef struct _q_event_t q_event_t;
+struct _q_event_t
+{
+ int size;
+ q_event_type event_type;
+ union _type
+ {
+ q_event_data_http_t q_event_data_http;
+ q_event_control_t q_event_control;
+ } type;
+
+ q_event_t *next;
+};
+
+typedef struct _queue_t
+{
+ da_bool_t having_data;
+
+ q_event_t *control_head;
+ q_event_t *data_head;
+
+ pthread_mutex_t mutex_queue;
+ pthread_cond_t cond_queue;
+
+ int queue_size;
+}queue_t;
+
+void Q_init_queue(queue_t *queue);
+void Q_destroy_queue(queue_t *queue);
+
+void Q_init_q_event(q_event_t *q_event);
+void Q_destroy_q_event(q_event_t **q_event);
+
+da_result_t Q_make_control_event(q_event_type_control control_type, q_event_t **out_event);
+
+da_result_t Q_make_http_data_event(q_event_type_data data_type, q_event_t **out_event);
+da_result_t Q_set_status_code_on_http_data_event(q_event_t *q_event, int status_code);
+da_result_t Q_set_http_body_on_http_data_event(q_event_t *q_event, int body_len, char *body_data);
+da_result_t Q_set_error_type_on_http_data_event(q_event_t *q_event, int error_type);
+
+
+da_bool_t Q_push_event(const queue_t *in_queue, const q_event_t *in_event);
+da_bool_t Q_push_event_without_lock(const queue_t *in_queue, const q_event_t *in_event);
+void Q_pop_event(const queue_t *in_queue, q_event_t **out_event);
+
+#define GET_IS_Q_HAVING_DATA(QUEUE) (QUEUE->having_data)
+
+void Q_goto_sleep(const queue_t *in_queue);
+void Q_wake_up(const queue_t *in_queue);
+
+
+#endif
diff --git a/agent/include/download-agent-interface.h b/agent/include/download-agent-interface.h
new file mode 100755
index 0000000..44081bd
--- /dev/null
+++ b/agent/include/download-agent-interface.h
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Interface_H
+#define _Download_Agent_Interface_H
+
+#ifndef EXPORT_API
+#define EXPORT_API __attribute__((visibility("default")))
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "download-agent-defs.h"
+#include <stdarg.h>
+
+/**
+ * @struct user_paused_info_t
+ * @brief Download Agent will send its state through this structure.
+ * @see da_paused_info_cb
+ * @par
+ * This is used only by callback /a user_paused_info_t. \n
+ */
+typedef struct {
+ /// download request id for this notification
+ int download_id;
+} user_paused_info_t;
+
+/**
+ * @struct user_progress_info_t
+ * @brief Download Agent will send current downloading file's information through this structure.
+ * @see da_progress_info_cb
+ * @par
+ * This is used only by callback /a da_progress_info_cb. \n
+ */
+typedef struct {
+ /// download request id for this updated download information
+ int download_id;
+ /// received size of chunked data.
+ unsigned long int received_size;
+} user_progress_info_t;
+
+/**
+ * @struct user_download_info_t
+ * @brief Download Agent will send current download's information through this structure.
+ * @see da_started_info_cb
+ * @par
+ * This is used only by callback /a da_started_info_cb. \n
+ */
+typedef struct {
+ /// download request id for this updated download information
+ int download_id;
+ /// file's mime type from http header.
+ char *file_type;
+ /// file size from http header.
+ unsigned long int file_size;
+ /// This is temporary file path.
+ char *tmp_saved_path;
+ /// This is the file name for showing to user.
+ char *content_name;
+ /// etag string value for resume download,
+ char *etag;
+} user_download_info_t;
+
+typedef struct {
+ /// download request id for this updated download information
+ int download_id;
+ /// This has only file name for now.
+ char *saved_path;
+ /// etag string value for resume download,
+ /// This is returned when the download is failed and the etag is received from content server
+ char *etag;
+ /// convey error code if necessary, or it is zero.
+ int err;
+ /// http status code if necessary, or it is zero.
+ int http_status;
+} user_finished_info_t;
+
+typedef struct {
+ const char **request_header;
+ int request_header_count;
+ const char *install_path;
+ const char *file_name;
+ const char *temp_file_path; /* For resume download, the "etag" value should be existed together */
+ const char *etag; /* For resume download */
+ const char *pkg_name; /* For system resource */
+ void *user_data;
+} extension_data_t;
+
+/**
+ * @typedef da_paused_cb
+ * @brief Download Agent will call this function to paused its state.
+ *
+ * This is user callback function registered on \a da_init. \n
+ *
+ * @remarks For the most of time, this state is just informative, so, user doesn't need to do any action back to Download Agent.
+ *
+ * @warning Download will be holding until getting user confirmation result through the function.
+ *
+ * @param[in] state state from Download Agent
+ * @param[in] user_param user parameter which is set with \a DA_FEATURE_USER_DATA
+ *
+ * @see da_init
+ * @see da_client_cb_t
+ */
+typedef void (*da_paused_info_cb) (user_paused_info_t *paused_info, void *user_param);
+
+/**
+ * @brief Download Agent will call this function to update received size of download-requested file.
+ *
+ * This is user callback function registered on \a da_init. \n
+ * This is informative, so, user doesn't need to do any action back to Download Agent.\n
+ *
+ * @param[in] progress_info updated downloading information
+ * @param[in] user_param user parameter which is set with \a DA_FEATURE_USER_DATA
+ *
+ * @see da_init
+ * @see da_client_cb_t
+ */
+typedef void (*da_progress_info_cb) (user_progress_info_t *progress_info, void *user_param);
+
+/**
+ * @brief Download Agent will call this function to update mime type, temp file name, total file sizeand installed path.
+ *
+ * This is user callback function registered on \a da_init. \n
+ * This is informative, so, user doesn't need to do any action back to Download Agent.\n
+ *
+ * @param[in] download_info updated download information
+ * @param[in] user_param user parameter which is set with \a DA_FEATURE_USER_DATA
+ *
+ * @see da_init
+ * @see da_client_cb_t
+ */
+typedef void (*da_started_info_cb) (user_download_info_t *download_info, void *user_param);
+
+typedef void (*da_finished_info_cb) (user_finished_info_t *finished_info, void *user_param);
+ /**
+ * @struct da_client_cb_t
+ * @brief This structure convey User's callback functions for \a da_init
+ * @see da_init
+ */
+typedef struct {
+ /// callback to convey download information
+ da_started_info_cb update_dl_info_cb;
+ /// callback to convey downloading information while downloading including received file size
+ da_progress_info_cb update_progress_info_cb;
+ /// callback to convey saved path
+ da_finished_info_cb finished_info_cb;
+ /// callback to convey etag value
+ da_paused_info_cb paused_info_cb;
+} da_client_cb_t;
+
+/**
+ * @fn int da_init (da_client_cb_t *da_client_callback)
+ * @brief This function initiates Download Agent and registers user callback functions.
+ * @warning This should be called at once when client application is initialized before using other Download Agent APIs
+ * @warning This function is paired with da_deinit function.
+ *
+ * @pre None.
+ * @post None.
+ *
+ * @param[in] da_client_callback User callback function structure. The type is struct data pointer.
+ * @return DA_RESULT_OK for success, or DA_ERR_XXX for fail. DA_ERR_XXX is defined at download-agent-def.h.
+ * @remarks User MUST call this function first rather than any other DA APIs. \n
+ * Please do not call UI code at callback function in direct. \n
+ * It is better that it returns as soon as copying the data of callback functon. \n
+ * @see da_deinit
+ * @par Example
+ * @code
+ * #include <download-agent-interface.h>
+ *
+ * void da_started_info_cb(user_download_info_t *download_info,void *user_param);
+ * void da_progress_info_cb(user_downloading_info_t *downloading_info,void *user_param);
+ * void da_finished_cb(user_finished_info_t *complted_info, void *user_param);
+ * void da_paused_info_cb(user_paused_info_t *paused_info, void *user_param);
+ *
+ * int download_initialize()
+ * {
+ * int da_ret;
+ * da_client_cb_t da_cb = {0};
+ *
+ * da_cb.update_dl_info_cb = &update_download_info_cb;
+ * da_cb.update_progress_info_cb = &progress_info_cb;
+ * da_cb.finished_info_cb = &finished_info_cb;
+ * da_cb.paused_info_cb = &paused_cb;
+ *
+ * da_ret = da_init (&da_cb, 0);
+ * if (da_ret == DA_RESULT_OK) {
+ * // printf("successed\n");
+ * return true;
+ * } else {
+ * // printf("failed with error code %d\n", da_ret);
+ * return fail;
+ * }
+ * }
+ * @endcode
+ */
+EXPORT_API int da_init(da_client_cb_t *da_client_callback);
+
+ /**
+ * @fn int da_deinit ()
+ * @brief This function deinitiates Download Agent.
+ *
+ * This function destroys all infomation for client manager.
+ * When Download Agent is not used any more, please call this function.
+ * Usually when client application is destructed, this is needed.
+ *
+ * @remarks This is paired with da_init. \n
+ * The client Id should be the one from /a da_init(). \n
+ * Otherwise, it cannot excute to deinitialize. \n
+ *
+ * @pre da_init() must be called in advance.
+ * @post None.
+ *
+ * @return DA_RESULT_OK for success, or DA_ERR_XXX for fail. DA_ERR_XXX is defined at download-agent-def.h.
+ * @see da_init
+ * @par Example
+ * @code
+ * #include <download-agent-interface.h>
+ *
+ *
+ * int download_deinitialize()
+ * {
+ * int da_ret;
+ * da_ret = da_deinit();
+ * if(da_ret == DA_RESULT_OK) {
+ * // printf("successed\n");
+ * return true;
+ * } else {
+ * // printf("failed with error code %d\n", da_ret);
+ * return fail;
+ * }
+ * }
+ @endcode
+ */
+EXPORT_API int da_deinit();
+
+ /**
+ * @fn int da_start_download(const char *url, int *download_id)
+ * @brief This function starts to download a content on passed URL.
+ *
+ * Useful information and result are conveyed through following callbacks.
+ * @li da_started_info_cb
+ * @li da_progress_cb
+ *
+ * @pre da_init() must be called in advance.
+ * @post None.
+ * @remarks
+ * Downloaded file is automatically registered to system. (e.g. File DB) \n
+ * If there is another file has same name on registering directory, new one's name would have numbering postfix. \n
+ * (e.g. abc.mp3 to abc_1.mp3)
+ *
+ * @param[in] url url to start download
+ * @param[out] download_id assigned download request id for this URL
+ * @return DA_RESULT_OK for success, or DA_ERR_XXX for fail. DA_ERR_XXX is defined at download-agent-def.h.
+ *
+ * @see None.
+ *
+ * @par Example
+ * @code
+ * #include <download-agent-interface.h>
+ *
+ * int da_ret;
+ * int download_id;
+ * char *url = "http://www.test.com/sample.mp3";
+ *
+ * da_ret = da_start_download(url,&download_id);
+ * if (da_ret == DA_RESULT_OK)
+ * printf("download requesting is successed\n");
+ * else
+ * printf("download requesting is failed with error code %d\n", da_ret);
+ * @endcode
+ */
+EXPORT_API int da_start_download(const char *url, int *download_id);
+
+/**
+* @fn int da_start_download_with_extension(const char *url, extension_data_t ext_data, int *download_id)
+* @brief This function starts to download a content on passed URL with passed extension.
+*
+* Useful information and result are conveyed through following callbacks.
+* @li da_started_info_cb
+* @li da_progress_cb
+*
+* @pre da_init() must be called in advance.
+* @post None.
+* @remarks This API operation is exactly same with da_start_download(), except for input properties. \n
+*
+* @param[in] url url to start download
+* @param[in] ext_data extension data
+* @param[out] download_id assigned download request id for this URL
+* @return DA_RESULT_OK for success, or DA_ERR_XXX for fail. DA_ERR_XXX is defined at download-agent-def.h.
+*
+*
+* @par Example
+* @code
+ #include <download-agent-interface.h>
+
+ int da_ret;
+ int download_id;
+ extension_data_t ext_data = {0,};
+ const char *url = "https://www.test.com/sample.mp3";
+ const char *install_path = "/myFiles/music";
+ const char *my_data = strdup("data");
+ ext_data.install_path = install_path;
+ ext_data.user_data = (void *)my_data;
+
+ da_ret = da_start_download_with_extension(url, &download_id, &ext_data);
+ if (da_ret == DA_RESULT_OK)
+ printf("download requesting is successed\n");
+ else
+ printf("download requesting is failed with error code %d\n", da_ret);
+ @endcode
+*/
+EXPORT_API int da_start_download_with_extension(const char *url,
+ extension_data_t *ext_data,
+ int *download_id
+);
+
+
+/**
+ * @fn int da_cancel_download(int download_id)
+ * @brief This function cancels a download for passed download_id.
+ *
+ * Client can use this function if user wants to cancel already requested download.
+ *
+ * @remarks Should check return value. \n
+ * If return value is not DA_RESULT_OK, then previous requested download can be keep downloading.
+ * @remarks After calling this function, all information for the download_id will be deleted. So, client cannot request anything for the download_id.
+ *
+ * @pre There should be exist ongoing or suspended download for download_id.
+ * @post None.
+ *
+ * @param[in] download_id download request id
+ * @return DA_RESULT_OK for success, or DA_ERR_XXX for fail
+ *
+ * @see None.
+ *
+ * @par Example
+ * @code
+ #include <download-agent-interface.h>
+
+ int da_ret;
+ int download_id;
+
+ da_ret = da_cancel_download(download_id);
+ if(da_ret == DA_RESULT_OK) {
+ // printf("download with [%d] is successfully canceled.\n", download_id);
+ }
+ else {
+ // in this case, downloading with download_id is keep ongoing.
+ printf("failed to cancel with error code %d\n", da_ret);
+ }
+ @endcode
+ */
+EXPORT_API int da_cancel_download(int download_id);
+
+
+/**
+ * @fn int da_suspend_download(int download_id)
+ * @brief This function suspends downloading for passed download_id.
+ *
+ * Client can use this function if user wants to suspend already requested download.
+ *
+ * @remarks Should check return value. \n
+ * If return value is not DA_RESULT_OK, then previous requested download can be keep downloading.
+ * @remarks After calling this function, all information for the download_id will be remained. So, client can request resume for the download_id.
+ * @remarks Client should cancel or resume for this download_id, or all information for the download_id will be leaved forever.
+ *
+ * @pre There should be exist ongoing download for download_id.
+ * @post None.
+ *
+ * @param[in] download_id download request id
+ * @return DA_RESULT_OK for success, or DA_ERR_XXX for fail
+ *
+ * @see da_resume_download()
+ * @see da_cancel_download()
+ *
+ * @par Example
+ * @code
+ #include <download-agent-interface.h>
+
+ int da_ret;
+ int download_id;
+
+ da_ret = da_suspend_download(download_id);
+ if(da_ret == DA_RESULT_OK) {
+ // printf("download with [%d] is successfully suspended.\n", download_id);
+ }
+ else {
+ // in this case, downloading with download_id is keep ongoing.
+ printf("failed to suspend with error code %d\n", da_ret);
+ }
+ @endcode
+ */
+EXPORT_API int da_suspend_download(int download_id);
+
+EXPORT_API int da_suspend_download_without_update(int download_id);
+/**
+ * @fn int da_resume_download(int download_id)
+ * @brief This function resumes downloading for passed download_id.
+ *
+ * Client can use this function if user wants to resume suspended download.
+ *
+ * @remarks Should check return value. \n
+ * If return value is not DA_RESULT_OK, then requested download can be not to resume.
+ *
+ * @pre There should be exist suspended download for download_id.
+ * @post None.
+ *
+ * @param[in] download_id download request id
+ * @return DA_RESULT_OK for success, or DA_ERR_XXX for fail
+ *
+ * @see da_suspend_download()
+ *
+ * @par Example
+ * @code
+ #include <download-agent-interface.h>
+
+ int da_ret;
+ int download_id;
+
+ da_ret = da_resume_download(download_id);
+ if(da_ret == DA_RESULT_OK) {
+ // printf("download with [%d] is successfully resumed.\n", download_id);
+ }
+ else {
+ // in this case, downloading with download_id is keep suspended.
+ printf("failed to resume with error code %d\n", da_ret);
+ }
+ @endcode
+ */
+EXPORT_API int da_resume_download(int download_id);
+
+/**
+ * @fn int da_is_valid_download_id(int download_id)
+ * @brief This function return the download id is valid and the download thread is still alive.
+ *
+ * Client can use this function if user wants to resume download.
+ * If the download id is vaild and the download thread is alive, it can resume download with using da_resume_download()
+ * If the the download thread was already terminated due to restarting the process,
+ * it can resume download with using da_start_download_with_extension()
+ *
+ *
+ *
+ * @remarks Should check return value. \n
+ * If return value is not DA_RESULT_OK, then requested download can be not to resume.
+ *
+ * @pre There should be exist suspended download for download_id.
+ * @post None.
+ *
+ * @param[in] download_id download request id
+ * @return 1 for success, or 0 for fail
+ *
+ */
+EXPORT_API int da_is_valid_download_id(int download_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_Download_Agent_Interface_H
+
+
diff --git a/agent/include/download-agent-mime-util.h b/agent/include/download-agent-mime-util.h
new file mode 100755
index 0000000..5f143e9
--- /dev/null
+++ b/agent/include/download-agent-mime-util.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Mime_Table_H
+#define _Download_Agent_Mime_Table_H
+
+#include "download-agent-type.h"
+
+#define NO_EXTENSION_NAME_STR "dat"
+
+#define DD_MIME_STR "application/vnd.oma.dd+xml"
+#define DD_EXT_STR "*.dd"
+#define DRM_MIME_MSG_STR "application/vnd.oma.drm.message"
+#define DRM_EXT_STR "*.dm"
+#define DRM_MIME_CONTENT_STR "application/vnd.oma.drm.content"
+
+typedef struct {
+ char *standard;
+ char *normal;
+} Ext_translation_table;
+
+da_bool_t is_ambiguous_MIME_Type(const char *in_mime_type);
+da_bool_t da_get_extension_name_from_url(char *url, char **ext);
+da_result_t da_mime_get_ext_name(char *mime, char **ext);
+da_bool_t da_get_file_name_from_url(char *url, char **name) ;
+void delete_prohibited_char(char *szTarget, int str_len);
+#endif
diff --git a/agent/include/download-agent-plugin-conf.h b/agent/include/download-agent-plugin-conf.h
new file mode 100755
index 0000000..2c4f55f
--- /dev/null
+++ b/agent/include/download-agent-plugin-conf.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Plugin_Conf_H
+#define _Download_Agent_Plugin_Conf_H
+
+#include "download-agent-type.h"
+#include "download-agent-interface.h"
+#include "download-agent-utils.h"
+
+da_result_t get_user_agent_string(char **uagent_str);
+char *get_proxy_address(void);
+
+#endif
diff --git a/agent/include/download-agent-plugin-http-interface.h b/agent/include/download-agent-plugin-http-interface.h
new file mode 100755
index 0000000..b9698bb
--- /dev/null
+++ b/agent/include/download-agent-plugin-http-interface.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Plugin_Http_Interface_H
+#define _Download_Agent_Plugin_Http_Interface_H
+
+#include "download-agent-type.h"
+#include "download-agent-http-msg-handler.h"
+
+typedef enum {
+ PI_HTTP_METHOD_GET = 1,
+ PI_HTTP_METHOD_POST = 2,
+ PI_HTTP_METHOD_HEAD = 3
+} pi_http_method_t;
+
+
+typedef struct _input_for_tranx_t {
+ pi_http_method_t http_method;
+
+ char *proxy_addr;
+ queue_t *queue;
+
+ http_msg_request_t* http_msg_request;
+} input_for_tranx_t;
+
+
+
+da_result_t PI_http_init(void);
+void PI_http_deinit(void);
+
+da_result_t PI_http_start_transaction(const input_for_tranx_t *input_for_tranx, int *out_tranx_id);
+da_result_t PI_http_cancel_transaction(int in_tranx_id, da_bool_t abort_option);
+da_result_t PI_http_disconnect_transaction(int in_tranx_id);
+void PI_http_pause_transaction(int transaction_id);
+void PI_http_unpause_transaction(int transaction_id);
+
+#endif
+
diff --git a/agent/include/download-agent-plugin-libsoup.h b/agent/include/download-agent-plugin-libsoup.h
new file mode 100755
index 0000000..8160042
--- /dev/null
+++ b/agent/include/download-agent-plugin-libsoup.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Plugin_Libsoup_H
+#define _Download_Agent_Plugin_Libsoup_H
+
+#include <string.h>
+#include <libsoup/soup.h>
+
+#include "download-agent-http-queue.h"
+#include "download-agent-pthread.h"
+#include "download-agent-plugin-http-interface.h"
+
+typedef struct _pi_session_table_t {
+ da_bool_t is_using;
+ SoupSession *session;
+ SoupMessage *msg;
+ queue_t *queue;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ da_bool_t is_paused;
+} pi_session_table_t;
+
+extern pi_session_table_t pi_session_table[];
+
+#define MAX_SESSION_COUNT DA_MAX_DOWNLOAD_REQ_AT_ONCE
+#define MAX_TIMEOUT 60 // second
+
+#define IS_VALID_SESSION_TABLE_ENTRY(ENTRY) ((((ENTRY) < 0) || ((ENTRY) > MAX_SESSION_COUNT-1)) ? 0 : 1)
+
+
+#define GET_SESSION_FROM_TABLE_ENTRY(ENTRY) (pi_session_table[ENTRY].session)
+#define GET_MSG_FROM_TABLE_ENTRY(ENTRY) (pi_session_table[ENTRY].msg)
+#define GET_QUEUE_FROM_TABLE_ENTRY(ENTRY) (pi_session_table[ENTRY].queue)
+
+
+da_bool_t _pi_http_is_valid_input_for_tranx(const input_for_tranx_t *input_for_tranx);
+
+void _pi_http_init_session_table_entry(const int in_session_table_entry);
+void _pi_http_destroy_session_table_entry(const int in_session_table_entry);
+int _pi_http_get_avaiable_session_table_entry(void);
+
+da_bool_t _pi_http_register_queue_to_session_table(const int session_table_entry, const queue_t *in_queue);
+da_bool_t _pi_http_register_session_to_session_table(const int in_session_table_entry, SoupSession *session);
+da_bool_t _pi_http_register_msg_to_session_table(const int in_session_table_entry, SoupMessage *msg);
+
+queue_t *_pi_http_get_queue_from_session_table_entry(const int in_session_table_entry);
+int _pi_http_get_session_table_entry_from_message(SoupMessage *msg);
+
+void _pi_http_store_read_data_to_queue(SoupMessage *msg, const char *body_data, int received_body_len);
+void _pi_http_store_read_header_to_queue(SoupMessage *msg, const char *sniffedType);
+void _pi_http_store_neterr_to_queue(SoupMessage *msg);
+
+
+void _pi_http_finished_cb(SoupSession *session, SoupMessage *msg, gpointer data);
+void _pi_http_restarted_cb(SoupMessage *msg, gpointer data);
+void _pi_http_gotheaders_cb(SoupMessage *msg, gpointer data);
+void _pi_http_contentsniffed_cb(SoupMessage *msg, const char *sniffedType, GHashTable *params, gpointer data);
+void _pi_http_gotchunk_cb(SoupMessage *msg, SoupBuffer *chunk, gpointer data);
+
+
+#endif
diff --git a/agent/include/download-agent-pthread.h b/agent/include/download-agent-pthread.h
new file mode 100755
index 0000000..8523567
--- /dev/null
+++ b/agent/include/download-agent-pthread.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Pthread_H
+#define _Download_Agent_Pthread_H
+
+#include <pthread.h>
+#include <errno.h>
+#include <time.h>
+
+#include "download-agent-type.h"
+#include "download-agent-debug.h"
+
+#define _da_thread_mutex_init(mutex_add, attr) { \
+ int ret = 0; \
+ do{ \
+ ret = pthread_mutex_init(mutex_add, attr); \
+ if (0 == ret){ \
+ break; \
+ } \
+ else if(EINVAL == ret){ \
+ DA_LOG_ERR(Default, "pthread_mutex_init FAIL with EINVAL."); \
+ break; \
+ } \
+ else if(ENOMEM == ret){ \
+ DA_LOG_ERR(Default, "pthread_mutex_init FAIL with ENOMEM."); \
+ break; \
+ } \
+ else{ \
+ DA_LOG_ERR(Default, "pthread_mutex_init FAIL with %d.", ret); \
+ break; \
+ } \
+ }while(1); \
+ }
+
+#define _da_thread_cond_init(cond_add, attr) do{ \
+ if (0 != pthread_cond_init(cond_add, attr)){\
+ DA_LOG_ERR(Default, "pthread_cond_init FAIL");} \
+ }while(0)
+
+
+
+#define _da_thread_mutex_lock(mutex_add) {\
+ int ret = 0;\
+ do{\
+ ret = pthread_mutex_lock(mutex_add);\
+ if (0 == ret){\
+ break;\
+ }\
+ else if(EINVAL == ret){\
+ DA_LOG_ERR(Default, "pthread_mutex_lock FAIL with EINVAL.");\
+ break;\
+ }\
+ else if(EDEADLK == ret){\
+ DA_LOG_ERR(Default, "pthread_mutex_lock FAIL with EDEADLK.");\
+ break;\
+ }\
+ else{\
+ DA_LOG_ERR(Default, "pthread_mutex_lock FAIL with %d.", ret);\
+ break;\
+ }\
+ }while(1);\
+ }
+
+
+#define _da_thread_mutex_unlock(mutex_add) {\
+ int ret = 0;\
+ do{\
+ ret = pthread_mutex_unlock(mutex_add);\
+ if (0 == ret){\
+ break;\
+ }\
+ else if(EINVAL == ret){\
+ DA_LOG_ERR(Default, "pthread_mutex_unlock FAIL with EINVAL.");\
+ break;\
+ }\
+ else if(EPERM == ret){\
+ DA_LOG_ERR(Default, "pthread_mutex_unlock FAIL with EPERM.");\
+ break;\
+ }\
+ else{\
+ DA_LOG_ERR(Default, "pthread_mutex_unlock FAIL with %d.", ret);\
+ break;\
+ }\
+ }while(1);\
+ }
+
+
+#define _da_thread_cond_signal(cond_add) do{ \
+ if (0 != pthread_cond_signal(cond_add)){\
+ DA_LOG_ERR(Default, "pthread_cond_signal FAIL");} \
+ }while(0)
+
+
+
+#define _da_thread_cond_wait(cond_add, mutex_add) do{ \
+ if (0 != pthread_cond_wait(cond_add, mutex_add)){\
+ DA_LOG_ERR(Default, "pthread_cond_wait FAIL");} \
+ }while(0)
+
+#define _da_thread_cond_timed_wait(cond_add, mutex_add, time) do{ \
+ if (0 != pthread_cond_timedwait(cond_add, mutex_add, time)){\
+ DA_LOG_ERR(Default, "pthread_cond_wait FAIL");} \
+ }while(0)
+
+
+#define _da_thread_cond_destroy(cond_add) do{ \
+ if (0 != pthread_cond_destroy(cond_add)){\
+ DA_LOG_ERR(Default, "pthread_cond_destroy FAIL");} \
+ }while(0)
+
+#define _da_thread_mutex_destroy(mutex_add) {\
+ int ret = 0;\
+ do{\
+ ret = pthread_mutex_destroy(mutex_add);\
+ if (0 == ret){\
+ break;\
+ }\
+ else if(EINVAL == ret){\
+ DA_LOG_ERR(Default, "pthread_mutex_destroy FAIL with EINVAL.");\
+ break;\
+ }\
+ else if(EBUSY == ret){\
+ DA_LOG_ERR(Default, "pthread_mutex_destroy FAIL with EBUSY.");\
+ break;\
+ }\
+ else{\
+ DA_LOG_ERR(Default, "pthread_mutex_destroy FAIL with %d.", ret);\
+ break;\
+ }\
+ }while(1);\
+ }
+
+#endif
diff --git a/agent/include/download-agent-type.h b/agent/include/download-agent-type.h
new file mode 100755
index 0000000..86fa5ca
--- /dev/null
+++ b/agent/include/download-agent-type.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Types_H
+#define _Download_Agent_Types_H
+
+#include "download-agent-defs.h"
+
+typedef int da_result_t;
+typedef int da_bool_t;
+
+#define IS_NOT_VALID_ID(x) (x <= DA_INVALID_ID)
+
+#define DA_MAX_URI_LEN 1024
+#define DA_MAX_FULL_PATH_LEN 356 // need configuration
+#define DA_MAX_FILE_PATH_LEN 256 // need configuration
+#define DA_MAX_STR_LEN 256
+#define DA_MAX_MIME_STR_LEN 256
+#define DA_MAX_PROXY_ADDR_LEN 64 // e.g. 100.200.300.400:10000
+
+#endif
+
diff --git a/agent/include/download-agent-utils-dl-id-history.h b/agent/include/download-agent-utils-dl-id-history.h
new file mode 100755
index 0000000..3e32048
--- /dev/null
+++ b/agent/include/download-agent-utils-dl-id-history.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Utils_Hash_Table_H
+#define _Download_Agent_Utils_Hash_Table_H
+
+#include "download-agent-pthread.h"
+
+typedef struct _dl_id_history_t dl_id_history_t;
+struct _dl_id_history_t {
+ int starting_num;
+ int cur_dl_id;
+ pthread_mutex_t mutex;
+};
+
+da_result_t init_dl_id_history(dl_id_history_t *dl_id_history);
+da_result_t deinit_dl_id_history(dl_id_history_t *dl_id_history);
+
+int get_available_dl_id(dl_id_history_t *dl_id_history);
+
+
+#endif /* _Download_Agent_Utils_Hash_Table_H */
diff --git a/agent/include/download-agent-utils.h b/agent/include/download-agent-utils.h
new file mode 100755
index 0000000..488cf3c
--- /dev/null
+++ b/agent/include/download-agent-utils.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _Download_Agent_Utils_H
+#define _Download_Agent_Utils_H
+
+#include <time.h>
+#include "download-agent-defs.h"
+#include "download-agent-interface.h"
+#include "download-agent-dl-mgr.h"
+
+#define SAVE_FILE_BUFFERING_SIZE_50KB (50*1024)
+#define SAVE_FILE_BUFFERING_SIZE_5MB (5*1024*1024)
+
+#define DA_SLEEP(x) \
+ do \
+ { \
+ struct timespec interval,remainder; \
+ interval.tv_sec = (unsigned int)((x)/1000); \
+ interval.tv_nsec = (((x)-(interval.tv_sec*1000))*1000000); \
+ nanosleep(&interval,&remainder); \
+ } while(0)
+
+typedef enum {
+ DA_MIME_TYPE_NONE,
+ DA_MIME_TYPE_DRM1_MESSATE,
+ DA_MIME_TYPE_END
+} da_mime_type_id_t;
+
+void get_random_number(int *out_num);
+da_result_t get_available_dd_id(int *available_id);
+da_result_t get_extension_from_mime_type(char *mime_type, char **extension);
+da_mime_type_id_t get_mime_type_id(char *content_type);
+da_bool_t is_valid_url(const char *url, da_result_t *err_code);
+
+int read_data_from_file(char *file, char**out_buffer);
+da_result_t move_file(const char *from_path, const char *to_path);
+void remove_file(const char *file_path);
+char *_stristr(const char *long_str, const char *find_str);
+
+#endif