The base model is changed
authorJungki Kwak <jungki.kwak@samsung.com>
Tue, 21 Aug 2012 10:10:00 +0000 (19:10 +0900)
committerJungki Kwak <jungki.kwak@samsung.com>
Tue, 21 Aug 2012 10:10:00 +0000 (19:10 +0900)
The base model change the libdownload-agent package to the download-provider daemon package
modified:   CMakeLists.txt
modified:   debian/changelog
modified:   include/url_download.h
modified:   include/url_download_private.h
modified:   packaging/capi-web-url-download.spec
new file:   sample/ipc_test.c
modified:   src/url_download.c
new file:   src/url_download_provider.c

CMakeLists.txt
debian/changelog
include/url_download.h
include/url_download_private.h [changed mode: 0755->0644]
packaging/capi-web-url-download.spec
sample/ipc_test.c [new file with mode: 0644]
src/url_download.c
src/url_download_provider.c [new file with mode: 0644]

index 58b5f46..8a35d49 100644 (file)
@@ -4,14 +4,21 @@ SET(fw_name "capi-web-url-download")
 
 PROJECT(${fw_name})
 
+OPTION(ENABLE_PROVIDER "Support download through download-provider daemon" ON)
+
 SET(CMAKE_INSTALL_PREFIX /usr)
 SET(PREFIX ${CMAKE_INSTALL_PREFIX})
 
 SET(INC_DIR include)
 INCLUDE_DIRECTORIES(${INC_DIR})
 
-SET(requires "dlog capi-base-common libdownload-agent bundle")
-SET(pc_requires "capi-base-common")
+IF (ENABLE_PROVIDER)
+       SET(requires "dlog capi-base-common bundle capi-appfw-app-manager capi-appfw-application download-provider")
+ELSE (ENABLE_PROVIDER)
+       SET(requires "dlog capi-base-common bundle libdownload-agent")
+ENDIF (ENABLE_PROVIDER)
+MESSAGE(STATUS "PACKAGES : ${requires}")
+SET(pc_requires "capi-base-common capi-appfw-application")
 
 INCLUDE(FindPkgConfig)
 pkg_check_modules(${fw_name} REQUIRED ${requires})
@@ -31,7 +38,13 @@ ADD_DEFINITIONS("-DSLP_DEBUG")
 
 SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=/usr/lib")
 
-aux_source_directory(src SOURCES)
+IF (ENABLE_PROVIDER)
+    ADD_DEFINITIONS("-DENABLE_DOWNLOAD_PROVIDER")
+       SET(SOURCES src/url_download_provider.c)
+ELSE (ENABLE_PROVIDER)
+       SET(SOURCES src/url_download.c)
+ENDIF (ENABLE_PROVIDER)
+MESSAGE(STATUS "SOURCES : ${SOURCES}")
 ADD_LIBRARY(${fw_name} SHARED ${SOURCES})
 
 TARGET_LINK_LIBRARIES(${fw_name} ${${fw_name}_LDFLAGS})
index 1fb8f4a..8867bc6 100644 (file)
@@ -1,3 +1,26 @@
+capi-web-url-download (0.0.5-0) unstable; urgency=low
+
+  * Git: slp/api/url-download
+  * Tag: capi-web-url-download_0.0.5-0
+
+  * Change to request cancel according to state
+  * Add exception handling code at start function
+  * Add initialize the callback data when destroying
+  * Add error code about max downloading item.
+  * Remove unused variable and modify wrong API name.
+  * Modify a make file to define the list of test case's source code.
+
+ -- Jungki Kwak <jungki.kwak@samsung.com>  Thu, 10 May 2012 10:46:37 +0900
+
+capi-web-url-download (0.0.4-0) unstable; urgency=low
+
+  * Git: slp/api/url-download
+  * Tag: capi-web-url-download_0.0.4-0
+
+  * Add a service operation define for the download manager application.
+
+ -- Jungki Kwak <jungki.kwak@samsung.com>  Fri, 23 Mar 2012 18:02:24 +0900
+
 capi-web-url-download (0.0.3-0) unstable; urgency=low
 
   * Git: slp/api/url-download
index cc5d4b7..764e4fd 100644 (file)
@@ -18,6 +18,7 @@
 #define __TIZEN_WEB_URL_DOWNLOAD_H__
 
 #include <tizen.h>
+#include <app.h>
 
 #ifdef __cplusplus
 extern "C"
@@ -59,6 +60,8 @@ typedef enum
        URL_DOWNLOAD_ERROR_SSL_FAILED = TIZEN_ERROR_WEB_CLASS | 0x23, /**< SSL negotiation failed */
        URL_DOWNLOAD_ERROR_INVALID_URL = TIZEN_ERROR_WEB_CLASS | 0x24, /**< Invalid URL */
        URL_DOWNLOAD_ERROR_INVALID_DESTINATION = TIZEN_ERROR_WEB_CLASS | 0x25, /**< Invalid destination */
+       URL_DOWNLOAD_ERROR_TOO_MANY_DOWNLOADS = TIZEN_ERROR_WEB_CLASS | 0x26, /**< Full of available downloading items */
+       URL_DOWNLOAD_ERROR_ALREADY_COMPLETED = TIZEN_ERROR_WEB_CLASS | 0x27, /**< The download is already completed */
 } url_download_error_e;
 
 
@@ -71,6 +74,7 @@ typedef enum
        URL_DOWNLOAD_STATE_DOWNLOADING, /**< The download is currently running */
        URL_DOWNLOAD_STATE_PAUSED, /**< The download is waiting to resume or stop */
        URL_DOWNLOAD_STATE_COMPLETED, /**< The download is completed. */
+       URL_DOWNLOAD_STATE_FAILED, /**< The download failed. */
 } url_download_state_e;
 
 
@@ -78,13 +82,16 @@ typedef enum
  * @brief Called when the download is started.
  *
  * @param [in] download The download handle
+ * @param [in] content_name The content name to display at UI layer
+ * @param [in] mime_type The MIME type string
  * @param [in] user_data The user data passed from url_download_set_started_cb()
  * @pre url_download_start() will cause this callback if you register this callback using url_download_set_started_cb()
  * @see url_download_start()
  * @see url_download_set_started_cb()
  * @see url_download_unset_started_cb()
  */
-typedef void (*url_download_started_cb) (url_download_h download, void *user_data);
+typedef void (*url_download_started_cb) (url_download_h download,
+       const char *content_name, const char *mime_type, void *user_data);
 
 
 /**
@@ -104,13 +111,13 @@ typedef void (*url_download_paused_cb) (url_download_h download, void *user_data
  * @brief Called when the download is completed.
  *
  * @param [in] download The download handle
- * @param [in] path The absolute path to the downloaded file
+ * @param [in] installed_path The absolute path to the downloaded file
  * @param [in] user_data The user data passed from url_download_set_completed_cb()
  * @pre This callback function will be invoked when the download is completed if you register this callback using url_download_set_paused_cb()
  * @see url_download_set_completed_cb()
  * @see url_download_unset_completed_cb()
  */
-typedef void (*url_download_completed_cb) (url_download_h download, const char * path, void *user_data);
+typedef void (*url_download_completed_cb) (url_download_h download, const char *installed_path, void *user_data);
 
 
 /**
@@ -179,6 +186,26 @@ int url_download_create(url_download_h *download);
 
 
 /**
+ * @brief Creates a download handle with the given identifier
+ *
+ * @remarks The @a download must be released with url_download_destroy() by you.\n
+ * The g_type_init() should be called when creating a main loop by user side. \n
+ * Because the libsoup, which is http stack library of download module, use gobject internally.
+ * @param [in] id The identifier for the download unique within the application.
+ * @param [out] download A download handle to be newly created on success
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #URL_DOWNLOAD_ERROR_NONE Successful
+ * @retval #URL_DOWNLOAD_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #URL_DOWNLOAD_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #URL_DOWNLOAD_ERROR_IO_ERROR Internal I/O error
+ * @post The download state will be #URL_DOWNLOAD_STATE_READY
+ * @see url_download_create()
+ * @see url_download_destroy()
+ */
+int url_download_create_by_id(int id, url_download_h *download);
+
+
+/**
  * @brief Destroys the URL download handle.
  *
  * @param [in] download The download handle
@@ -261,6 +288,109 @@ int url_download_get_destination(url_download_h download, char **path);
 
 
 /**
+ * @brief Sets the name for the downloaded file.
+ *
+ * @details The file will be downloaded to the specified destination as the given file name.
+ * If the file name is not specified, the downloaded file is saved to an auto-generated file name in the destination.
+ *
+ * @remarks This function should be called before downloading (see url_download_start())
+ * @param [in] download The download handle
+ * @param [in] file_name The file name for the downloaded file
+ *  If the @a name is NULL, it clears the previous value.
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #URL_DOWNLOAD_ERROR_NONE Successful
+ * @retval #URL_DOWNLOAD_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #URL_DOWNLOAD_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #URL_DOWNLOAD_ERROR_INVALID_STATE Invalid state
+ * @pre The download state must be #URL_DOWNLOAD_STATE_READY or #URL_DOWNLOAD_STATE_COMPLETED.
+ * @see url_download_get_file_name()
+ */
+int url_download_set_file_name(url_download_h download, const char *file_name);
+
+
+/**
+ * @brief Gets the name for the downloaded file.
+ *
+ * @remarks The @a file_name must be released with free() by you.
+ * @param [in] download The download handle
+ * @param [out] file_name The file name for the downloaded file
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #URL_DOWNLOAD_ERROR_NONE Successful
+ * @retval #URL_DOWNLOAD_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #URL_DOWNLOAD_ERROR_OUT_OF_MEMORY Out of memory
+ * @see url_download_set_file_name()
+ */
+int url_download_get_file_name(url_download_h download, char **file_name);
+
+
+/**
+ * @brief Sets the service to launch when the notification for the download is selected from the notification tray.
+ * @details When the notification for the download is selected from the notification tray, the application which is described by the specified service is launched. \n
+ * If you want to launch the current application, use the explicit launch of the @ref CAPI_SERVICE_MODULE API
+ * @remarks If the service is not set, the selected notification will be cleared from both the notification tray and the status bar without any action.
+ * @param[in] download The download handle
+ * @param[in] service The service handle to launch when the notification for the download is selected \n
+ *     If the @a service is NULL, it clears the previous value.
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #URL_DOWNLOAD_ERROR_NONE Successful
+ * @retval #URL_DOWNLOAD_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #URL_DOWNLOAD_ERROR_OUT_OF_MEMORY Out of memory
+ * @see url_download_get_notification()
+ * @see service_create()
+ */
+int url_download_set_notification(url_download_h download, service_h service);
+
+/**
+ * @brief Gets the service to launch when the notification for the download is selected from the notification tray
+ * @remarks The @a service must be released with service_destroy() by you.
+ * @param[in] download The download handle
+ * @param[out] service The service handle to launch when the notification is selected
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #URL_DOWNLOAD_ERROR_NONE Successful
+ * @retval #URL_DOWNLOAD_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #URL_DOWNLOAD_ERROR_OUT_OF_MEMORY Out of memory
+ * @see url_download_set_notification()
+ */
+int url_download_get_notification(url_download_h download, service_h *service);
+
+
+/**
+ * @brief Gets the absolute path to the downloaded file
+ *
+ * @remarks This function returns #URL_DOWNLOAD_ERROR_INVALID_STATE if the download is not completed. \n
+ * The @a path must be released with free() by you.
+ * @param [in] download The download handle
+ * @param [out] path The absolute path to the downloaded file
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #URL_DOWNLOAD_ERROR_NONE Successful
+ * @retval #URL_DOWNLOAD_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #URL_DOWNLOAD_ERROR_OUT_OF_MEMORY Out of memory
+ * @pre The download state must be #URL_DOWNLOAD_STATE_COMPLETED.
+ * @see url_download_set_file_name()
+ * @see url_download_set_destination()
+ */
+int url_download_get_downloaded_file(url_download_h download, char **path);
+
+
+/**
+ * @brief Gets the MIME type of the downloaded file
+ *
+ * @remarks This function returns #URL_DOWNLOAD_ERROR_INVALID_STATE if the download has not been started. \n
+ * The @a mime_type must be released with free() by you.
+ * @param [in] download The download handle
+ * @param [out] mime_type The MIME type of the downloaded file
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #URL_DOWNLOAD_ERROR_NONE Successful
+ * @retval #URL_DOWNLOAD_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #URL_DOWNLOAD_ERROR_OUT_OF_MEMORY Out of memory
+ * @see url_download_set_file_name()
+ * @see url_download_set_destination()
+ * @see url_download_get_downloaded_file()
+ */
+int url_download_get_mime(url_download_h download, char **mime_type);
+
+
+/**
  * @brief Adds an HTTP header field to the download request
  *
  * @details The given HTTP header field will be included with the HTTP request of the download request. \n
@@ -506,6 +636,7 @@ int url_download_unset_progress_cb(url_download_h download);
  *
  * @remarks The URL is the mandatory information to start the download.
  * @param [in] download The download handle
+ * @param [out] id The identifier for the download unique within the application.
  * @return 0 on success, otherwise a negative error value.
  * @retval #URL_DOWNLOAD_ERROR_NONE Successful
  * @retval #URL_DOWNLOAD_ERROR_INVALID_PARAMETER Invalid parameter
@@ -523,7 +654,7 @@ int url_download_unset_progress_cb(url_download_h download);
  * @see url_download_unset_started_cb()
  * @see url_download_started_cb()
  */
-int url_download_start(url_download_h download);
+int url_download_start(url_download_h download, int *id);
 
 
 /**
@@ -547,7 +678,6 @@ int url_download_start(url_download_h download);
  */
 int url_download_pause(url_download_h download);
 
-
 /**
  * @brief Stops the download, asynchronously.
  *
@@ -583,7 +713,6 @@ int url_download_stop(url_download_h download);
  */
 int url_download_get_state(url_download_h download, url_download_state_e *state);
 
-
 /**
  * @brief Retrieves all HTTP header fields to be included with the download
  * @details This function calls url_download_http_header_field_cb() once for each HTTP header field added.\n
old mode 100755 (executable)
new mode 100644 (file)
index 0116c92..f9481a0
 #define __TIZEN_WEB_URL_DOWNLOAD_PRIVATE_H__
 
 #include <bundle.h>
+#ifndef ENABLE_DOWNLOAD_PROVIDER
 #include <download-agent-interface.h>
+#endif
 
 #ifdef __cplusplus
 extern "C"
 {
 #endif
 
+#ifndef ENABLE_DOWNLOAD_PROVIDER
 typedef da_client_cb_t *url_download_agent_h;
+#endif
 
 /**
  * url_download_cb_s
@@ -49,14 +53,25 @@ struct url_download_cb_s {
 };
 
 struct url_download_s {
+#ifndef ENABLE_DOWNLOAD_PROVIDER
        url_download_agent_h agent;
        da_handle_t id;
+#else
+       uint id;
+       uint enable_notification;
+       int requestid;
+#endif
        struct url_download_cb_s callback;
        url_download_state_e state;
        char *url;
        char *destination;
        bundle *http_header;
        char *completed_path;
+       char *content_name;
+       char *mime_type;
+       uint file_size;
+       int sockfd;
+       pthread_t callback_thread_pid;
 };
 
 #ifdef __cplusplus
index 5219ddd..b1a85fd 100644 (file)
@@ -1,16 +1,23 @@
+%define ENABLE_DOWNLOAD_PROVIDER 1
 
 Name:  capi-web-url-download
 Summary:       CAPI for content download with web url
-Version:       0.0.3
-Release:       1
+Version:       0.0.7
+Release:       2
 Group:         TO_BE_FILLED_IN
 License:       TO_BE_FILLED_IN
 URL:           N/A
 Source0:       %{name}-%{version}.tar.gz
 BuildRequires: pkgconfig(capi-base-common)
-BuildRequires: pkgconfig(libdownload-agent)
 BuildRequires: pkgconfig(bundle)
 BuildRequires: pkgconfig(dlog)
+%if %ENABLE_DOWNLOAD_PROVIDER
+BuildRequires: pkgconfig(capi-appfw-app-manager)
+BuildRequires: pkgconfig(capi-appfw-application)
+BuildRequires: pkgconfig(download-provider)
+%else
+BuildRequires: pkgconfig(libdownload-agent)
+%endif
 BuildRequires: cmake
 BuildRequires: expat-devel
 
@@ -29,7 +36,7 @@ CAPI for content downloading with web url (developement files)
 %setup -q
 
 %build
-cmake . -DCMAKE_INSTALL_PREFIX="/usr/lib"
+cmake . -DCMAKE_INSTALL_PREFIX="/"
 
 make %{?jobs:-j%jobs}
 
@@ -51,3 +58,17 @@ rm -rf %{buildroot}
 /usr/lib/pkgconfig/capi-web-url-download.pc
 /usr/include/web/url_download.h
 
+%changelog
+* Mon Aug 16 2012 Jungki Kwak <jungki.kwak@samsung.com>
+- Add new APIs for notification function
+- The TC is changed due to change of url_download_start
+- When unseting the callback function, the callback should be initialized although the error is happened.
+- It remove the stop function when is called twice when destroying handle
+- Add pc requries for app.h
+
+* Mon Aug 08 2012 Jungki Kwak <jungki.kwak@samsung.com>
+- Change requestid to INTEGER from String
+
+* Mon Aug 06 2012 Jungki Kwak <jungki.kwak@samsung.com>
+- The base model is changed to download provider daemon
+
diff --git a/sample/ipc_test.c b/sample/ipc_test.c
new file mode 100644 (file)
index 0000000..33d00b4
--- /dev/null
@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "web/url_download.h"
+#include "log.h"
+
+bool exit_process_flag = false;
+
+void download_manager_started_cb (url_download_h download, void *user_data)
+{
+    TRACE_DEBUG_MSG("started");
+}
+void download_manager_completed_cb (url_download_h download, const char * path, void *user_data)
+{
+    TRACE_DEBUG_MSG("download_manager_completed_cb (%s)",path);
+    exit_process_flag = true;
+}
+void download_manager_progress_cb (url_download_h download, unsigned long long received, unsigned long long total, void *user_data)
+{
+    TRACE_DEBUG_MSG("progress (%d/%d)",received,total);
+}
+
+int main(int argc, char** argv)
+{
+    url_download_h download;
+    exit_process_flag = false;
+    // create download.
+    url_download_create(&download);
+    url_download_set_url(download, "abcdefghigk");
+    url_download_set_destination(download, "1234567890everywhere");
+
+    url_download_set_started_cb(download, download_manager_started_cb, NULL);
+    url_download_set_completed_cb(download, download_manager_completed_cb, NULL);
+    url_download_set_progress_cb(download, download_manager_progress_cb, NULL);
+
+    // start....
+    url_download_start(download);
+    while(!exit_process_flag)
+    {
+        sleep(5);
+    }
+    // pasuse
+    //url_download_pause(&download);
+    // resume
+    //url_download_stop(&download);
+
+    url_download_destroy(download);
+    TRACE_DEBUG_MSG("exit...........");
+    exit(EXIT_SUCCESS);
+}
index 4c67c59..2c57b47 100644 (file)
@@ -74,11 +74,9 @@ static const char* url_download_error_to_string(int error_code)
        case URL_DOWNLOAD_ERROR_CONNECTION_TIMED_OUT:
                error_name = "CONNECTION_TIMED_OUT";
                break;
-
        case URL_DOWNLOAD_ERROR_FIELD_NOT_FOUND:
                error_name = "FIELD_NOT_FOUND";
                break;
-
        case URL_DOWNLOAD_ERROR_NO_SPACE:
                error_name = "NO_SPACE";
                break;
@@ -91,15 +89,14 @@ static const char* url_download_error_to_string(int error_code)
        case URL_DOWNLOAD_ERROR_SSL_FAILED:
                error_name = "SSL_FAILED";
                break;
-
        case URL_DOWNLOAD_ERROR_INVALID_URL:
                error_name = "INVALID_URL";
                break;
-
        case URL_DOWNLOAD_ERROR_INVALID_DESTINATION:
                error_name = "INVALID_DESTINATION";
                break;
-
+       case URL_DOWNLOAD_ERROR_TOO_MANY_DOWNLOADS:
+               error_name = "FULL_OF_MAX_DOWNLOAD_ITEMS";
        default:
                error_name = "UNKNOWN";
                break;
@@ -261,7 +258,8 @@ static url_download_error_e url_download_agent_error(int error)
 
        case DA_ERR_INVALID_INSTALL_PATH:
                return URL_DOWNLOAD_ERROR_INVALID_DESTINATION;
-
+       case DA_ERR_ALREADY_MAX_DOWNLOAD:
+               return URL_DOWNLOAD_ERROR_TOO_MANY_DOWNLOADS;
        default:
                return URL_DOWNLOAD_ERROR_IO_ERROR;
        }
@@ -321,7 +319,7 @@ static bool is_available_download_data(url_download_h download)
        return ret;
 }
 
-static void url_download_agent_state_cb(user_notify_info_t *notify_info, voiduser_data)
+static void url_download_agent_state_cb(user_notify_info_t *notify_info, void *user_data)
 {
        url_download_h download = NULL;
        url_download_state_e state = -1;
@@ -531,6 +529,9 @@ int url_download_destroy(url_download_h download)
                download->completed_path = NULL;
        }
 
+       memset(&(download->callback), 0x00, sizeof(struct url_download_cb_s));
+       download->id = -1;
+
        url_download_agent_destroy(download->agent);
 
        head = _download_list;
@@ -1153,6 +1154,7 @@ static int url_download_start_download(url_download_h download)
        }
        else
        {
+               download->state = URL_DOWNLOAD_STATE_DOWNLOADING;
                return URL_DOWNLOAD_ERROR_NONE;
        }
 }
@@ -1181,6 +1183,11 @@ int url_download_start(url_download_h download)
                return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
        }
 
+       if (!is_available_download_data(download))
+       {
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, "download item is already destroyed!!!!!!!!");
+       }
+
        switch (download->state)
        {
        case URL_DOWNLOAD_STATE_COMPLETED:
@@ -1225,12 +1232,12 @@ int url_download_stop(url_download_h download)
        {
                return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
        }
-/*
+
        if (download->state != URL_DOWNLOAD_STATE_DOWNLOADING)
        {
                return url_download_error_invalid_state(__FUNCTION__, download);
        }
-*/
+
        if (da_cancel_download(download->id))
        {
                return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, "failed to stop the download");
diff --git a/src/url_download_provider.c b/src/url_download_provider.c
new file mode 100644 (file)
index 0000000..cbf2fd8
--- /dev/null
@@ -0,0 +1,1247 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <pthread.h>
+#include <signal.h>
+
+#include <app_manager.h>
+
+#include <dlog.h>
+#include <url_download.h>
+#include <url_download_private.h>
+#include <download-provider.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "TIZEN_N_URL_DOWNLOAD"
+
+#define STATE_IS_RUNNING(_download_) \
+        (_download_->state == URL_DOWNLOAD_STATE_DOWNLOADING \
+        || _download_->state == URL_DOWNLOAD_STATE_PAUSED)
+
+
+#define STRING_IS_INVALID(_string_) \
+       (_string_ == NULL || _string_[0] == '\0')
+
+static int url_download_resume(url_download_h download);
+static int url_download_get_all_http_header_fields(
+               url_download_h download, char ***fields, int *fields_length);
+
+url_download_error_e url_download_provider_error(int error)
+{
+       switch (error) {
+               case DOWNLOAD_ERROR_NONE:
+                       return URL_DOWNLOAD_ERROR_NONE;
+
+               case DOWNLOAD_ERROR_CONNECTION_FAILED:
+                       return URL_DOWNLOAD_ERROR_CONNECTION_FAILED;
+
+               case DOWNLOAD_ERROR_NETWORK_UNREACHABLE:
+                       return URL_DOWNLOAD_ERROR_NETWORK_UNREACHABLE;
+
+               case DOWNLOAD_ERROR_CONNECTION_TIMED_OUT:
+                       return URL_DOWNLOAD_ERROR_CONNECTION_TIMED_OUT;
+
+               case DOWNLOAD_ERROR_INVALID_DESTINATION:
+                       return URL_DOWNLOAD_ERROR_INVALID_DESTINATION;
+
+               case DOWNLOAD_ERROR_NO_SPACE:
+                       return URL_DOWNLOAD_ERROR_NO_SPACE;
+
+               case DOWNLOAD_ERROR_INVALID_URL:
+                       return URL_DOWNLOAD_ERROR_INVALID_URL;
+
+               case DOWNLOAD_ERROR_TOO_MANY_DOWNLOADS:
+                       return URL_DOWNLOAD_ERROR_TOO_MANY_DOWNLOADS;
+
+               case DOWNLOAD_ERROR_ALREADY_COMPLETED:
+                       return URL_DOWNLOAD_ERROR_ALREADY_COMPLETED;
+
+               default:
+                       return URL_DOWNLOAD_ERROR_IO_ERROR;
+       }
+}
+
+const char* url_download_error_to_string(int error_code)
+{
+       char *error_name = NULL;
+
+       switch (error_code) {
+               case URL_DOWNLOAD_ERROR_NONE:
+                       error_name = "ERROR_NONE";
+                       break;
+               case URL_DOWNLOAD_ERROR_INVALID_PARAMETER:
+                       error_name = "INVALID_PARAMETER";
+                       break;
+               case URL_DOWNLOAD_ERROR_OUT_OF_MEMORY:
+                       error_name = "OUT_OF_MEMORY";
+                       break;
+               case URL_DOWNLOAD_ERROR_IO_ERROR:
+                       error_name = "IO_ERROR";
+                       break;
+               case URL_DOWNLOAD_ERROR_NETWORK_UNREACHABLE:
+                       error_name = "NETWORK_UNREACHABLE";
+                       break;
+               case URL_DOWNLOAD_ERROR_CONNECTION_TIMED_OUT:
+                       error_name = "CONNECTION_TIMED_OUT";
+                       break;
+               case URL_DOWNLOAD_ERROR_FIELD_NOT_FOUND:
+                       error_name = "FIELD_NOT_FOUND";
+                       break;
+               case URL_DOWNLOAD_ERROR_NO_SPACE:
+                       error_name = "NO_SPACE";
+                       break;
+               case URL_DOWNLOAD_ERROR_INVALID_STATE:
+                       error_name = "INVALID_STATE";
+                       break;
+               case URL_DOWNLOAD_ERROR_CONNECTION_FAILED:
+                       error_name = "CONNECTION_FAILED";
+                       break;
+               case URL_DOWNLOAD_ERROR_SSL_FAILED:
+                       error_name = "SSL_FAILED";
+                       break;
+               case URL_DOWNLOAD_ERROR_INVALID_URL:
+                       error_name = "INVALID_URL";
+                       break;
+               case URL_DOWNLOAD_ERROR_INVALID_DESTINATION:
+                       error_name = "INVALID_DESTINATION";
+                       break;
+               case URL_DOWNLOAD_ERROR_TOO_MANY_DOWNLOADS:
+                       error_name = "FULL_OF_MAX_DOWNLOAD_ITEMS";
+                       break;
+               case URL_DOWNLOAD_ERROR_ALREADY_COMPLETED:
+                       error_name = "ALREADY_COMPLETED";
+                       break;
+               default:
+                       error_name = "UNKNOWN";
+                       break;
+       }
+       return error_name;
+}
+
+int url_download_error(const char *function, int error_code, const char *description)
+{
+       const char *error_name = NULL;
+
+       error_name = url_download_error_to_string(error_code);
+       if (description)
+               LOGE("[%s] %s(0x%08x) : %s", function, error_name, error_code, description);
+       else
+               LOGE("[%s] %s(0x%08x)", function, error_name, error_code);
+
+       return error_code;
+}
+
+const char* url_download_state_to_string(url_download_state_e state)
+{
+       switch (state)
+       {
+       case URL_DOWNLOAD_STATE_READY:
+               return "READY";
+
+       case URL_DOWNLOAD_STATE_DOWNLOADING:
+               return "DOWNLOADING";
+
+       case URL_DOWNLOAD_STATE_PAUSED:
+               return "PAUSED";
+
+       case URL_DOWNLOAD_STATE_COMPLETED:
+               return "COMPLETED";
+
+       default:
+               return "INVALID";
+       }
+}
+
+int url_download_error_invalid_state(const char *function, url_download_h download)
+{
+       LOGE("[%s] INVALID_STATE(0x%08x) : state(%s)",
+                function, URL_DOWNLOAD_ERROR_INVALID_STATE, url_download_state_to_string(download->state));
+
+       return URL_DOWNLOAD_ERROR_INVALID_STATE;
+}
+
+int ipc_receive_header(int fd)
+{
+       if(fd <= 0)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+
+       download_controls msgheader = 0;
+       if (read(fd, &msgheader, sizeof(download_controls)) < 0)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+
+       return msgheader;
+}
+
+int ipc_send_download_control(url_download_h download, download_controls type)
+{
+       if (download == NULL || download->sockfd <= 0)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+
+       // send control
+       if (send(download->sockfd, &type, sizeof(download_controls), 0) < 0)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+
+       return type;
+}
+
+// 1 thread / 1 download
+void *run_receive_event_server(void *args)
+{
+       fd_set rset, exceptset;
+       struct timeval timeout;
+       download_state_info stateinfo;
+       download_content_info downloadinfo;
+       downloading_state_info downloadinginfo;
+       download_request_state_info requeststateinfo;
+
+       url_download_h download = (url_download_h)args;
+
+       while(download && download->sockfd > 0) {
+               FD_ZERO(&rset);
+               FD_ZERO(&exceptset);
+               FD_SET(download->sockfd, &rset);
+               FD_SET(download->sockfd, &exceptset);
+               timeout.tv_sec = 3;
+
+               if (select((download->sockfd+1), &rset, 0, &exceptset, &timeout) < 0) {
+                       url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+                       if (download->callback.stopped) {
+                               download->callback.stopped(download,
+                               URL_DOWNLOAD_ERROR_IO_ERROR,
+                               download->callback.stopped_user_data);
+                       }
+                       break;
+               }
+
+               if (FD_ISSET(download->sockfd, &rset) > 0) {
+                       // read some message from socket.
+                       switch(ipc_receive_header(download->sockfd)) {
+                               case DOWNLOAD_CONTROL_GET_REQUEST_STATE_INFO :
+                                       LOGI("[%s] DOWNLOAD_CONTROL_GET_REQUEST_STATE_INFO (started pended request)",__FUNCTION__);
+                                       if (read(download->sockfd, &requeststateinfo, sizeof(download_request_state_info)) < 0) {
+                                               url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+                                               goto URL_DOWNLOAD_EVENT_THREAD_EXIT;
+                                       }
+                                       if (requeststateinfo.requestid > 0) {
+                                               if (requeststateinfo.requestid != download->requestid)
+                                                       goto URL_DOWNLOAD_EVENT_THREAD_EXIT;
+                                               download->requestid = requeststateinfo.requestid;
+                                               if (requeststateinfo.stateinfo.state == DOWNLOAD_STATE_FAILED) {
+                                                       download->state = URL_DOWNLOAD_STATE_READY;
+                                                       if (download->callback.stopped) {
+                                                               download->callback.stopped(download,
+                                                               url_download_provider_error(stateinfo.err),
+                                                               download->callback.stopped_user_data);
+                                                       }
+                                                       goto URL_DOWNLOAD_EVENT_THREAD_EXIT;
+                                               } else
+                                                       download->state = URL_DOWNLOAD_STATE_DOWNLOADING;
+                                       } else {
+                                               LOGE("[%s]Not Found request id (Wrong message)", __FUNCTION__);
+                                               download->state = URL_DOWNLOAD_STATE_READY;
+                                               if (download->callback.stopped) {
+                                                       download->callback.stopped(download,
+                                                       url_download_provider_error(stateinfo.err),
+                                                       download->callback.stopped_user_data);
+                                               }
+                                               goto URL_DOWNLOAD_EVENT_THREAD_EXIT;
+                                       }
+                                       break;
+                               case DOWNLOAD_CONTROL_GET_DOWNLOAD_INFO :
+                                       if (read(download->sockfd, &downloadinfo, sizeof(download_content_info)) < 0) {
+                                               url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+                                               goto URL_DOWNLOAD_EVENT_THREAD_EXIT;
+                                       }
+                                       LOGI("[%s] DOWNLOAD_CONTROL_GET_DOWNLOAD_INFO [%d]%",__FUNCTION__, downloadinfo.file_size);
+                                       download->state = URL_DOWNLOAD_STATE_DOWNLOADING;
+                                       download->file_size = downloadinfo.file_size;
+                                       if (downloadinfo.mime_type && strlen(downloadinfo.mime_type) > 0)
+                                               download->mime_type = strdup(downloadinfo.mime_type);
+                                       if (downloadinfo.content_name && strlen(downloadinfo.content_name) > 0) {
+                                               download->content_name = strdup(downloadinfo.content_name);
+                                               LOGI("content_name[%s] %", downloadinfo.content_name);
+                                       }
+                                       if (download->callback.started) {
+                                               download->callback.started(
+                                               download, download->content_name, download->mime_type,
+                                               download->callback.started_user_data);
+                                       }
+                                       break;
+                               case DOWNLOAD_CONTROL_GET_DOWNLOADING_INFO :
+                                       if (read(download->sockfd, &downloadinginfo, sizeof(downloading_state_info)) < 0) {
+                                               url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+                                               goto URL_DOWNLOAD_EVENT_THREAD_EXIT;
+                                       }
+                                       // call the function by download-callbacks table.
+                                       LOGI("[%s] DOWNLOAD_CONTROL_GET_DOWNLOADING_INFO [%d]%",__FUNCTION__, downloadinginfo.received_size);
+                                       if (download->callback.progress) {
+                                               download->callback.progress(
+                                               download,
+                                               downloadinginfo.received_size, download->file_size,
+                                               download->callback.progress_user_data);
+                                       }
+                                       if (downloadinginfo.saved_path &&
+                                                       strlen(downloadinginfo.saved_path) > 0) {
+                                               LOGI("[%s] saved path [%s]",__FUNCTION__, downloadinginfo.saved_path);
+                                               download->completed_path = strdup(downloadinginfo.saved_path);
+                                       }
+                                       break;
+                               case DOWNLOAD_CONTROL_GET_STATE_INFO :
+                                       if (read(download->sockfd, &stateinfo, sizeof(download_state_info)) < 0) {
+                                               url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+                                               goto URL_DOWNLOAD_EVENT_THREAD_EXIT;
+                                       }
+                                       // call the function by download-callbacks table.
+                                       LOGI("[%s] DOWNLOAD_CONTROL_GET_STATE_INFO state[%d]",__FUNCTION__, stateinfo.state);
+                                       switch (stateinfo.state) {
+                                               case DOWNLOAD_STATE_STOPPED:
+                                                       LOGI("DOWNLOAD_STATE_STOPPED");
+                                                       download->state = URL_DOWNLOAD_STATE_READY;
+                                                       if (download->callback.stopped) {
+                                                               download->callback.stopped(download,
+                                                               url_download_provider_error(stateinfo.err),
+                                                               download->callback.stopped_user_data);
+                                                       }
+                                                       // terminate this thread.
+                                                       goto URL_DOWNLOAD_EVENT_THREAD_EXIT;
+                                                       break;
+
+                                               case DOWNLOAD_STATE_DOWNLOADING:
+                                                       download->state = URL_DOWNLOAD_STATE_DOWNLOADING;
+                                                       LOGI("DOWNLOAD_STATE_DOWNLOADING");
+                                                       break;
+                                               case DOWNLOAD_STATE_PAUSE_REQUESTED:
+                                                       LOGI("DOWNLOAD_STATE_PAUSE_REQUESTED");
+                                                       break;
+                                               case DOWNLOAD_STATE_PAUSED:
+                                                       LOGI("DOWNLOAD_STATE_PAUSED");
+                                                       download->state = URL_DOWNLOAD_STATE_PAUSED;
+                                                       if (download->callback.paused)
+                                                               download->callback.paused(download, download->callback.paused_user_data);
+                                                       break;
+
+                                               case DOWNLOAD_STATE_FINISHED:
+                                                       LOGI("DOWNLOAD_STATE_FINISHED");
+                                                       download->state = URL_DOWNLOAD_STATE_COMPLETED;
+                                                       if (download->callback.completed)
+                                                               download->callback.completed(download, download->completed_path, download->callback.completed_user_data);
+                                                       // terminate this thread.
+                                                       goto URL_DOWNLOAD_EVENT_THREAD_EXIT;
+                                                       break;
+                                               case DOWNLOAD_STATE_READY:
+                                                       LOGI("DOWNLOAD_STATE_READY");
+                                                       break;
+                                               case DOWNLOAD_STATE_INSTALLING:
+                                                       LOGI("DOWNLOAD_STATE_INSTALLING");
+                                                       break;
+                                               case DOWNLOAD_STATE_FAILED:
+                                                       LOGI("DOWNLOAD_STATE_FAILED");
+                                                       download->state = URL_DOWNLOAD_STATE_READY;
+                                                       if (download->callback.stopped) {
+                                                               download->callback.stopped(download,
+                                                               url_download_provider_error(stateinfo.err),
+                                                               download->callback.stopped_user_data);
+                                                       }
+                                                       goto URL_DOWNLOAD_EVENT_THREAD_EXIT;
+                                                       break;
+                                               default:
+                                                       url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, "invalid state change event");
+                                                       if (download->callback.stopped) {
+                                                               download->state = URL_DOWNLOAD_STATE_READY;
+                                                               download->callback.stopped(download,
+                                                               URL_DOWNLOAD_ERROR_IO_ERROR,
+                                                               download->callback.stopped_user_data);
+                                                       }
+                                                       goto URL_DOWNLOAD_EVENT_THREAD_EXIT;
+                                                       break;
+                                       }
+
+                                       break;
+
+                               default :
+                                       url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, "Invalid message");
+                                       if (download->callback.stopped) {
+                                               download->state = URL_DOWNLOAD_STATE_READY;
+                                               download->callback.stopped(download,
+                                               URL_DOWNLOAD_ERROR_IO_ERROR,
+                                               download->callback.stopped_user_data);
+                                       }
+                                       goto URL_DOWNLOAD_EVENT_THREAD_EXIT;
+                                       break;
+                       }
+               } else if (FD_ISSET(download->sockfd, &exceptset) > 0) {
+                       url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, "IO Exception");
+                       if (download->callback.stopped) {
+                               download->state = URL_DOWNLOAD_STATE_READY;
+                               download->callback.stopped(download,
+                               URL_DOWNLOAD_ERROR_IO_ERROR,
+                               download->callback.stopped_user_data);
+                       }
+
+                       break;
+               } else {
+                       // wake up by timeout. run extra job.
+               }
+       }
+URL_DOWNLOAD_EVENT_THREAD_EXIT :
+       if (download && download->sockfd) {
+               FD_CLR(download->sockfd, &rset);
+               FD_CLR(download->sockfd, &exceptset);
+               if (download->sockfd)
+                       close(download->sockfd);
+                       download->sockfd = 0;
+       }
+       return NULL;
+}
+
+// fill the reqeust info.
+int url_download_create(url_download_h *download)
+{
+       url_download_h download_new;
+
+       if (download == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       download_new = (url_download_h)calloc(1, sizeof(struct url_download_s));
+       if (download_new == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_OUT_OF_MEMORY, NULL);
+
+       download_new->http_header = bundle_create();
+
+       if (!download_new->http_header) {
+               url_download_destroy(download_new);
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, "failed to initialize a bundle");
+       }
+
+       download_new->state = URL_DOWNLOAD_STATE_READY;
+       download_new->sockfd = 0;
+       *download = download_new;
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+int url_download_create_by_id(int id, url_download_h *download)
+{
+       int errorcode = URL_DOWNLOAD_ERROR_NONE;
+       if (id <= 0)
+               url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+       errorcode = url_download_create(download);
+       if (errorcode == URL_DOWNLOAD_ERROR_NONE)
+               (*download)->requestid = id;
+       return errorcode;
+}
+
+// disconnect from download-provider
+int url_download_destroy(url_download_h download)
+{
+       if (download == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (STATE_IS_RUNNING(download))
+               url_download_stop(download);
+
+       if (download->sockfd)
+               close(download->sockfd);
+       download->sockfd = 0;
+//     url_download_stop(download);
+       if (download->url)
+               free(download->url);
+       if (download->destination)
+               free(download->destination);
+       if (download->http_header)
+               free(download->http_header);
+       if (download->mime_type)
+               free(download->mime_type);
+       if (download->content_name)
+               free(download->content_name);
+       if (download->completed_path)
+               free(download->completed_path);
+       memset(&(download->callback), 0x00, sizeof(struct url_download_cb_s));
+       download->id = -1;
+       free(download);
+
+       download = NULL;
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+// connect to download-provider. then send request info.
+int url_download_start(url_download_h download, int *id)
+{
+       struct sockaddr_un clientaddr;
+
+       char **headers = NULL;
+       int header_length = 0;
+
+       if (!download || !download->url)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (download->state == URL_DOWNLOAD_STATE_DOWNLOADING)
+               return url_download_error_invalid_state(__FUNCTION__, download);
+
+       if (download->state == URL_DOWNLOAD_STATE_PAUSED)
+               return url_download_resume(download);
+
+       if (download->sockfd)
+               close(download->sockfd);
+       if ((download->sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+               LOGE("[%s]socket system error : %s",__FUNCTION__,strerror(errno));
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+       }
+
+       bzero(&clientaddr, sizeof clientaddr);
+       clientaddr.sun_family = AF_UNIX;
+       strcpy(clientaddr.sun_path, DOWNLOAD_PROVIDER_IPC);
+       if (connect(download->sockfd, (struct sockaddr*)&clientaddr, sizeof(clientaddr)) < 0) {
+               LOGE("[%s]connect system error : %s",__FUNCTION__,strerror(errno));
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+       }
+
+       download_request_info requestMsg;
+       memset(&requestMsg, 0x00, sizeof(download_request_info));
+       requestMsg.callbackinfo.started = (download->callback.started ? 1 : 0);
+       requestMsg.callbackinfo.paused = (download->callback.paused ? 1 : 0);
+       requestMsg.callbackinfo.completed = (download->callback.completed ? 1 : 0);
+       requestMsg.callbackinfo.stopped = (download->callback.stopped ? 1 : 0);
+       requestMsg.callbackinfo.progress = (download->callback.progress ? 1 : 0);
+       requestMsg.notification = download->enable_notification;
+
+       if (download->requestid > 0)
+               requestMsg.requestid = download->requestid;
+
+       if (download->url)
+               requestMsg.url.length = strlen(download->url);
+
+       if (download->destination)
+               requestMsg.install_path.length = strlen(download->destination);
+
+       if (download->content_name)
+               requestMsg.filename.length = strlen(download->content_name);
+
+       // headers test
+       if (url_download_get_all_http_header_fields(download, &headers, &header_length) !=
+                       URL_DOWNLOAD_ERROR_NONE) {
+               return url_download_error(__FUNCTION__,
+                               URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+       }
+       if (header_length > 0) {
+               int i=0;
+               requestMsg.headers.rows = header_length;
+               requestMsg.headers.str = (download_flexible_string*)calloc(requestMsg.headers.rows,
+                               sizeof(download_flexible_string));
+               for(i=0; i < requestMsg.headers.rows; i++)
+                       requestMsg.headers.str[i].length = strlen(headers[i]);
+       }
+
+       char *app_pkgname = NULL;
+       pid_t client_pid = getpid();
+       int errcode = app_manager_get_package(client_pid, &app_pkgname);
+       if (errcode == APP_MANAGER_ERROR_NONE)
+               requestMsg.client_packagename.length = strlen(app_pkgname);
+       else
+               LOGE("[%s] Failed to get app_pkgname app_manager_get_package",__FUNCTION__);
+
+       ipc_send_download_control(download, DOWNLOAD_CONTROL_START);
+
+       if (send(download->sockfd, &requestMsg, sizeof(download_request_info), 0) < 0) {
+               if (app_pkgname)
+                       free(app_pkgname);
+               LOGE("[%s]request send system error : %s",
+                               __FUNCTION__, strerror(errno));
+               return url_download_error(__FUNCTION__,
+                               URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+       }
+       if (requestMsg.client_packagename.length) {
+               if (send(download->sockfd, app_pkgname,
+                               requestMsg.client_packagename.length * sizeof(char), 0) < 0) {
+                       if (app_pkgname)
+                               free(app_pkgname);
+                       LOGE("[%s]request send system error : %s",
+                                       __FUNCTION__, strerror(errno));
+                       return url_download_error(__FUNCTION__,
+                                       URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+               }
+       }
+       if (app_pkgname)
+               free(app_pkgname);
+
+       if (requestMsg.url.length) {
+               if (send(download->sockfd, download->url,
+                               requestMsg.url.length * sizeof(char), 0) < 0) {
+                       LOGE("[%s]request send system error : %s",
+                                       __FUNCTION__, strerror(errno));
+                       return url_download_error(__FUNCTION__,
+                                       URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+               }
+       }
+       if (requestMsg.install_path.length) {
+               if (send(download->sockfd, download->destination,
+                               requestMsg.install_path.length * sizeof(char), 0) < 0) {
+                       LOGE("[%s]request send system error : %s",
+                                       __FUNCTION__, strerror(errno));
+                       return url_download_error(__FUNCTION__,
+                                       URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+               }
+       }
+       if (requestMsg.filename.length) {
+               if (send(download->sockfd, download->content_name,
+                               requestMsg.filename.length * sizeof(char), 0) < 0) {
+                       LOGE("[%s]request send system error : %s",
+                                       __FUNCTION__, strerror(errno));
+                       return url_download_error(__FUNCTION__,
+                                       URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+               }
+       }
+
+       if (requestMsg.headers.rows) {
+               int i=0;
+               for(i=0; i < requestMsg.headers.rows; i++) {
+                       if (send(download->sockfd, &requestMsg.headers.str[i],
+                                       sizeof(download_flexible_string), 0) < 0) {
+                               LOGE("[%s]request send system error : %s",
+                                               __FUNCTION__,strerror(errno));
+                               return url_download_error(__FUNCTION__,
+                                               URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+                       }
+                       if (send(download->sockfd, headers[i],
+                                       requestMsg.headers.str[i].length * sizeof(char), 0) < 0) {
+                               LOGE("[%s]request send system error : %s",
+                                               __FUNCTION__,strerror(errno));
+                               return url_download_error(__FUNCTION__,
+                                               URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+                       }
+               }
+               free(requestMsg.headers.str);
+       }
+
+       // Sync style
+       if (ipc_receive_header(download->sockfd) == DOWNLOAD_CONTROL_GET_REQUEST_STATE_INFO) {
+               download_request_state_info requeststateinfo;
+               if (read(download->sockfd, &requeststateinfo, sizeof(download_request_state_info)) < 0) {
+                       url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+                       return -1;
+               }
+               if (requeststateinfo.requestid > 0) {
+                       download->requestid = requeststateinfo.requestid;
+                       (*id) = requeststateinfo.requestid;
+               }
+               if (requeststateinfo.stateinfo.state == DOWNLOAD_STATE_DOWNLOADING) {
+                       // started download normally.
+                       download->state = URL_DOWNLOAD_STATE_DOWNLOADING;
+               }
+       } else {
+               url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+               url_download_stop(download);
+               return URL_DOWNLOAD_ERROR_IO_ERROR;
+       }
+
+       // capi need the thread for listening message from download-provider; this will deal the callbacks.
+       if (download->callback.completed
+               || download->callback.stopped
+               || download->callback.progress
+               || download->callback.paused) {
+               // check whether event thread is alive.
+               if (!download->callback_thread_pid
+                       || pthread_kill(download->callback_thread_pid, 0) != 0) {
+                       // if want to receive the events from download-provider.
+                       // create thread. it will listen the message through select().
+                       pthread_attr_t thread_attr;
+                       if (pthread_attr_init(&thread_attr) != 0)
+                               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_OUT_OF_MEMORY, NULL);
+                       if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED) != 0) {
+                               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_OUT_OF_MEMORY, NULL);
+                       }
+                       // create thread for receiving the client request.
+                       if (pthread_create(&download->callback_thread_pid, &thread_attr, run_receive_event_server, download) != 0)
+                               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_OUT_OF_MEMORY, NULL);
+               }
+       }
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+// send pause message
+int url_download_pause(url_download_h download)
+{
+       if (download == NULL || download->sockfd <= 0)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (download->state != URL_DOWNLOAD_STATE_DOWNLOADING)
+               return url_download_error_invalid_state(__FUNCTION__, download);
+
+       ipc_send_download_control(download, DOWNLOAD_CONTROL_PAUSE);
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+int url_download_resume(url_download_h download)
+{
+       if (download == NULL || download->sockfd <= 0)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (download->state != URL_DOWNLOAD_STATE_PAUSED)
+               return url_download_error_invalid_state(__FUNCTION__, download);
+
+       ipc_send_download_control(download, DOWNLOAD_CONTROL_RESUME);
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+
+// send stop message
+int url_download_stop(url_download_h download)
+{
+       if (download == NULL || download->sockfd <= 0)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (download->state != URL_DOWNLOAD_STATE_DOWNLOADING)
+               return url_download_error_invalid_state(__FUNCTION__, download);
+
+       ipc_send_download_control(download, DOWNLOAD_CONTROL_STOP);
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+int url_download_get_state(url_download_h download, url_download_state_e *state)
+{
+       if (download == NULL || state == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (download->sockfd
+               && download->callback_thread_pid <= 0) {  // only when does not use the callback.
+
+               ipc_send_download_control(download, DOWNLOAD_CONTROL_GET_STATE_INFO);
+
+               // Sync style
+               if (ipc_receive_header(download->sockfd) == DOWNLOAD_CONTROL_GET_STATE_INFO) {
+                       download_state_info stateinfo;
+                       if (read(download->sockfd, &stateinfo, sizeof(download_state_info)) < 0) {
+                               *state = download->state;
+                               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+                       }
+                       download->state = url_download_provider_error(stateinfo.state);
+               } else {
+                       *state = download->state;
+                       return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+               }
+       }
+       *state = download->state;
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+int url_download_set_url(url_download_h download, const char *url)
+{
+       char *url_dup = NULL;
+
+       if (download == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (STATE_IS_RUNNING(download))
+               return url_download_error_invalid_state(__FUNCTION__, download);
+
+       if (url != NULL) {
+               url_dup = strndup(url, strlen(url));
+
+               if (url_dup == NULL)
+                       return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_OUT_OF_MEMORY, NULL);
+       }
+
+       if (download->url != NULL)
+               free(download->url);
+
+       download->url = url_dup;
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+
+int url_download_get_url(url_download_h download, char **url)
+{
+       char *url_dup = NULL;
+
+       if (download == NULL || url == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (download->url != NULL) {
+               url_dup = strdup(download->url);
+
+               if (url_dup == NULL)
+                       return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_OUT_OF_MEMORY, NULL);
+       }
+
+       *url = url_dup;
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+
+int url_download_set_destination(url_download_h download, const char *path)
+{
+       char *path_dup = NULL;
+
+       if (download == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (STATE_IS_RUNNING(download))
+               return url_download_error_invalid_state(__FUNCTION__, download);
+
+       if (path != NULL) {
+               path_dup = strdup(path);
+
+               if (path_dup == NULL)
+                       return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_OUT_OF_MEMORY, NULL);
+       }
+
+       if (download->destination != NULL)
+               free(download->destination);
+
+       download->destination = path_dup;
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+
+int url_download_get_destination(url_download_h download, char **path)
+{
+       char *path_dup = NULL;
+
+       if (download == NULL || path == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (download->destination != NULL) {
+               path_dup = strdup(download->destination);
+
+               if (path_dup == NULL)
+                       return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_OUT_OF_MEMORY, NULL);
+       }
+
+       *path = path_dup;
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+int url_download_set_file_name(url_download_h download, const char *file_name)
+{
+       if (download == NULL || file_name == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (download->content_name)
+               free(download->content_name);
+       download->content_name = strdup(file_name);
+       if (download->content_name == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_OUT_OF_MEMORY, NULL);
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+int url_download_get_file_name(url_download_h download, char **file_name)
+{
+       char *filename_dup = NULL;
+
+       if (download == NULL || file_name == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (download->content_name != NULL) {
+               filename_dup = strdup(download->content_name);
+
+               if (filename_dup == NULL)
+                       return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_OUT_OF_MEMORY, NULL);
+       }
+
+       *file_name = filename_dup;
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+int url_download_set_notification(url_download_h download, service_h service)
+{
+       if (download == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+       if (service == NULL)
+               download->enable_notification = 0;
+       else
+               download->enable_notification = 1;
+       // service_h will be used later. it need to discuss more.
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+int url_download_get_notification(url_download_h download, service_h *service)
+{
+       int errorcode = URL_DOWNLOAD_ERROR_NONE;
+       return errorcode;
+}
+
+int url_download_get_downloaded_file(url_download_h download, char **path)
+{
+       char *path_dup = NULL;
+
+       if (download == NULL || path == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (download->completed_path != NULL) {
+               path_dup = strdup(download->completed_path);
+
+               if (path_dup == NULL)
+                       return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_OUT_OF_MEMORY, NULL);
+       }
+
+       *path = path_dup;
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+int url_download_get_mime(url_download_h download, char **mime_type)
+{
+       char *mime_dup = NULL;
+
+       if (download == NULL || mime_type == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (download->mime_type != NULL) {
+               mime_dup = strdup(download->mime_type);
+
+               if (mime_dup == NULL)
+                       return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_OUT_OF_MEMORY, NULL);
+       }
+
+       *mime_type = mime_dup;
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+int url_download_add_http_header_field(url_download_h download, const char *field, const char *value)
+{
+       if (download == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (STRING_IS_INVALID(field) || STRING_IS_INVALID(value))
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (STATE_IS_RUNNING(download))
+               return url_download_error_invalid_state(__FUNCTION__, download);
+
+       if (bundle_get_val(download->http_header, field))
+               bundle_del(download->http_header, field);
+
+       if (bundle_add(download->http_header, field, value))
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+
+int url_download_get_http_header_field(url_download_h download, const char *field, char **value)
+{
+       const char *bundle_value;
+       char *field_value_dup;
+
+       if (download == NULL || value == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (STRING_IS_INVALID(field))
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       bundle_value = bundle_get_val(download->http_header, field);
+
+       if (bundle_value == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_FIELD_NOT_FOUND, NULL);
+
+       field_value_dup = strdup(bundle_value);
+
+       if (field_value_dup == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_OUT_OF_MEMORY, NULL);
+
+       *value = field_value_dup;
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+
+int url_download_remove_http_header_field(url_download_h download, const char *field)
+{
+       if (download == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (STRING_IS_INVALID(field))
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, "invalid field");
+
+       if (STATE_IS_RUNNING(download))
+               return url_download_error_invalid_state(__FUNCTION__, download);
+
+       if (!bundle_get_val(download->http_header, field))
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_FIELD_NOT_FOUND, NULL);
+
+       if (bundle_del(download->http_header, field))
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_IO_ERROR, NULL);
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+
+int url_download_set_started_cb(url_download_h download, url_download_started_cb callback, void* user_data)
+{
+       if (download == NULL || callback == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (STATE_IS_RUNNING(download))
+               return url_download_error_invalid_state(__FUNCTION__, download);
+
+       download->callback.started = callback;
+       download->callback.started_user_data = user_data;
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+
+int url_download_unset_started_cb(url_download_h download)
+{
+       if (download == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (STATE_IS_RUNNING(download))
+//             return url_download_error_invalid_state(__FUNCTION__, download);
+               url_download_error_invalid_state(__FUNCTION__, download);
+
+       download->callback.started = NULL;
+       download->callback.started_user_data = NULL;
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+
+int url_download_set_paused_cb(url_download_h download, url_download_paused_cb callback, void* user_data)
+{
+       if (download == NULL || callback == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (STATE_IS_RUNNING(download))
+               return url_download_error_invalid_state(__FUNCTION__, download);
+
+       download->callback.paused = callback;
+       download->callback.paused_user_data = user_data;
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+
+int url_download_unset_paused_cb(url_download_h download)
+{
+       if (download == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (STATE_IS_RUNNING(download))
+//             return url_download_error_invalid_state(__FUNCTION__, download);
+               url_download_error_invalid_state(__FUNCTION__, download);
+
+       download->callback.paused = NULL;
+       download->callback.paused_user_data = NULL;
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+
+int url_download_set_completed_cb(url_download_h download, url_download_completed_cb callback, void* user_data)
+{
+       if (download == NULL || callback == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (STATE_IS_RUNNING(download))
+               return url_download_error_invalid_state(__FUNCTION__, download);
+
+       download->callback.completed = callback;
+       download->callback.completed_user_data = user_data;
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+
+int url_download_unset_completed_cb(url_download_h download)
+{
+       if (download == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (STATE_IS_RUNNING(download))
+//             return url_download_error_invalid_state(__FUNCTION__, download);
+               url_download_error_invalid_state(__FUNCTION__, download);
+
+       download->callback.completed = NULL;
+       download->callback.completed_user_data = NULL;
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+
+int url_download_set_stopped_cb(url_download_h download, url_download_stopped_cb callback, void* user_data)
+{
+       if (download == NULL || callback == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (STATE_IS_RUNNING(download))
+               return url_download_error_invalid_state(__FUNCTION__, download);
+
+       download->callback.stopped = callback;
+       download->callback.stopped_user_data = user_data;
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+
+int url_download_unset_stopped_cb(url_download_h download)
+{
+       if (download == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (STATE_IS_RUNNING(download))
+//             return url_download_error_invalid_state(__FUNCTION__, download);
+               url_download_error_invalid_state(__FUNCTION__, download);
+
+       download->callback.stopped = NULL;
+       download->callback.stopped_user_data = NULL;
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+
+int url_download_set_progress_cb(url_download_h download, url_download_progress_cb callback, void *user_data)
+{
+       if (download == NULL || callback == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (STATE_IS_RUNNING(download))
+               return url_download_error_invalid_state(__FUNCTION__, download);
+
+       download->callback.progress = callback;
+       download->callback.progress_user_data = user_data;
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+
+int url_download_unset_progress_cb(url_download_h download)
+{
+       if (download == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       if (STATE_IS_RUNNING(download))
+//             return url_download_error_invalid_state(__FUNCTION__, download);
+               url_download_error_invalid_state(__FUNCTION__, download);
+
+       download->callback.progress = NULL;
+       download->callback.progress_user_data = NULL;
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+typedef struct http_field_array_s{
+       char **array;
+       int array_length;
+       int position;
+} http_field_array_t;
+
+void url_download_get_all_http_header_fields_iterator(const char *field_name, const char *field_value, void *user_data)
+{
+       http_field_array_t *http_field_array;
+       char *field_buffer;
+       int field_buffer_length;
+       const char *field_delimiters = ": ";
+
+       http_field_array = user_data;
+
+       if (http_field_array == NULL) {
+               url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+               return;
+       }
+
+       // REF : http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
+       field_buffer_length = strlen(field_name) + strlen(field_delimiters) + strlen(field_value) + 1;
+
+       field_buffer = calloc(field_buffer_length, sizeof(char));
+
+       if (field_buffer == NULL) {
+               url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_OUT_OF_MEMORY, NULL);
+               return;
+       }
+
+       int len = snprintf(field_buffer, field_buffer_length, "%s%s%s", field_name, field_delimiters, field_value);
+       if (len == -1) {
+               if (field_buffer)
+                       free(field_buffer);
+               return;
+       } else if ( len > 0 )
+               field_buffer[len] = '\0';
+
+       http_field_array->array[http_field_array->position] = field_buffer;
+       http_field_array->position++;
+
+}
+
+int url_download_get_all_http_header_fields(url_download_h download, char ***fields, int *fields_length)
+{
+       http_field_array_t http_field_array;
+
+       if (download == NULL || fields == NULL || fields_length == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       http_field_array.position = 0;
+       http_field_array.array_length = bundle_get_count(download->http_header);
+       http_field_array.array = calloc(http_field_array.array_length, sizeof(char*));
+
+       if (http_field_array.array == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_OUT_OF_MEMORY, NULL);
+
+       bundle_iterate(download->http_header, url_download_get_all_http_header_fields_iterator, &http_field_array);
+
+       *fields = http_field_array.array;
+       *fields_length = http_field_array.array_length;
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+
+typedef struct {
+       url_download_h download;
+       url_download_http_header_field_cb callback;
+       void* user_data;
+       bool foreach_break;
+} foreach_context_http_header_field_t;
+
+static void url_download_foreach_http_header_field_iterator(const char *field_name, const char *field_value, void *user_data)
+{
+       foreach_context_http_header_field_t *foreach_context;
+
+       foreach_context = user_data;
+
+       if (foreach_context == NULL) {
+               url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+               return;
+       }
+
+
+       if (foreach_context->foreach_break == true)
+               return;
+
+       if (foreach_context->callback != NULL)
+               foreach_context->foreach_break = !foreach_context->callback(foreach_context->download,
+                        field_name, foreach_context->user_data);
+}
+
+int url_download_foreach_http_header_field(url_download_h download, url_download_http_header_field_cb callback, void *user_data)
+{
+       foreach_context_http_header_field_t foreach_context = {
+               .download = download,
+               .callback = callback,
+               .user_data = user_data,
+               .foreach_break = false
+       };
+
+       if (download == NULL || callback == NULL)
+               return url_download_error(__FUNCTION__, URL_DOWNLOAD_ERROR_INVALID_PARAMETER, NULL);
+
+       bundle_iterate(download->http_header, url_download_foreach_http_header_field_iterator, &foreach_context);
+
+       return URL_DOWNLOAD_ERROR_NONE;
+}
+