barbieri pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=2cb3466ddf8f52b5d012fcf02fbe4fa08e067559

commit 2cb3466ddf8f52b5d012fcf02fbe4fa08e067559
Author: Gustavo Sverzut Barbieri <barbi...@profusion.mobi>
Date:   Tue Nov 29 03:43:16 2016 -0200

    ecore_con_url: now on top of efl_net_dialer_http.
    
    Rewrite Ecore_Con_Url as a non-Eo (since it's just legacy) that is
    built on top of Efl_Net_Dialer_Http.
    
    Since there are some legacy behavior we do not want to expose in the
    new classes, hack around and manipulate the curl_easy_setopt()
    directly in those cases.
    
    This includes the cookies: there is no reason why we should expose
    independent files for read (COOKIEFILE) and write (COOKIEJAR), real
    world applications can manipulate the files directly, like copying
    from a template to a RDWR before using, etc.
---
 src/Makefile_Ecore_Con.am            |    5 +-
 src/lib/ecore_con/Ecore_Con.h        |   80 +-
 src/lib/ecore_con/Ecore_Con_Eo.h     |    1 -
 src/lib/ecore_con/Ecore_Con_Legacy.h |   21 -
 src/lib/ecore_con/ecore_con_url.c    | 2191 ++++++++++++++++------------------
 src/lib/ecore_con/efl_network_url.eo |   29 -
 6 files changed, 1077 insertions(+), 1250 deletions(-)

diff --git a/src/Makefile_Ecore_Con.am b/src/Makefile_Ecore_Con.am
index 82221e7..c3e51ae 100644
--- a/src/Makefile_Ecore_Con.am
+++ b/src/Makefile_Ecore_Con.am
@@ -33,8 +33,7 @@ ecore_con_eolian_files = \
         lib/ecore_con/efl_net_session.eo \
        lib/ecore_con/ecore_con_eet_base.eo \
        lib/ecore_con/ecore_con_eet_server_obj.eo \
-       lib/ecore_con/ecore_con_eet_client_obj.eo \
-       lib/ecore_con/efl_network_url.eo
+       lib/ecore_con/ecore_con_eet_client_obj.eo
 
 if HAVE_WINDOWS
 else
@@ -134,8 +133,6 @@ lib/ecore_con/efl_net_control-none.c \
 lib/ecore_con/efl_net_session-none.c
 endif
 
-EXTRA_DIST2 += lib/ecore_con/ecore_con_legacy.c
-
 # these are included rather than compiled out
 # so the structures can be embedded into the
 # object Private Data and allows functions to
diff --git a/src/lib/ecore_con/Ecore_Con.h b/src/lib/ecore_con/Ecore_Con.h
index cc2dd2b..393b94c 100644
--- a/src/lib/ecore_con/Ecore_Con.h
+++ b/src/lib/ecore_con/Ecore_Con.h
@@ -272,6 +272,22 @@ typedef void (*Ecore_Con_Dns_Cb)(const char *canonname,
 #include "Ecore_Con_Eo.h"
 #endif
 
+
+/**
+ * @struct _Ecore_Con_Url
+ * Used to provide legacy ABI/ABI compatibility with non-Eo applications.
+ * @ingroup Ecore_Con_Url_Group
+ */
+struct _Ecore_Con_Url;
+
+/**
+ * @typedef Ecore_Con_Url
+ * Used to provide legacy API/ABI compatibility with non-Eo applications.
+ * @ingroup Ecore_Con_Url_Group
+ */
+typedef struct _Ecore_Con_Url Ecore_Con_Url;
+
+
 /**
  * @addtogroup Ecore_Con_Events_Group
  * @{
@@ -362,16 +378,6 @@ typedef struct _Ecore_Con_Event_Server_Write 
Ecore_Con_Event_Server_Write;
  */
 typedef struct _Ecore_Con_Event_Proxy_Bind Ecore_Con_Event_Proxy_Bind;
 
-#ifdef EFL_BETA_API_SUPPORT
-/**
- * @typedef Efl_Network_Event_Url_Data
- * Used as the @p data param for the corresponding event
- * EFL_NETWORK_EVENT_URL_DATA
- * @ingroup Ecore_Con_Url_Group
- */
-typedef struct _Efl_Network_Event_Url_Data Efl_Network_Event_Url_Data;
-#endif
-
 /**
  * @typedef Ecore_Con_Event_Url_Data
  * Used as the @p data param for the corresponding event
@@ -386,16 +392,6 @@ typedef struct _Ecore_Con_Event_Url_Data 
Ecore_Con_Event_Url_Data;
  */
 typedef struct _Ecore_Con_Event_Url_Complete Ecore_Con_Event_Url_Complete;
 
-#ifdef EFL_BETA_API_SUPPORT
-/**
- * @typedef Efl_Network_Event_Url_Complete
- * Used as the @p data param for the corresponding event
- * EFL_NETWORK_EVENT_URL_COMPLETE
- * @ingroup Ecore_Con_Url_Group
- */
-typedef struct _Ecore_Con_Event_Url_Complete Efl_Network_Event_Url_Complete;
-#endif
-
 /**
  * @typedef Ecore_Con_Event_Url_Progress
  * Used as the @p data param for the corresponding event
@@ -403,16 +399,6 @@ typedef struct _Ecore_Con_Event_Url_Complete 
Efl_Network_Event_Url_Complete;
  */
 typedef struct _Ecore_Con_Event_Url_Progress Ecore_Con_Event_Url_Progress;
 
-#ifdef EFL_BETA_API_SUPPORT
-/**
- * @typedef Efl_Network_Event_Url_Progress
- * Used as the @p data param for the corresponding event
- * EFL_NETWORK_EVENT_URL_PROGRESS
- * @ingroup Ecore_Con_Url_Group
- */
-typedef struct _Ecore_Con_Event_Url_Progress Efl_Network_Event_Url_Progress;
-#endif
-
 /**
  * @struct _Ecore_Con_Event_Client_Add
  * Used as the @p data param for the @ref ECORE_CON_EVENT_CLIENT_ADD event
@@ -544,20 +530,6 @@ struct _Ecore_Con_Event_Proxy_Bind
    int port;                 /**< the proxy-bound port */
 };
 
-#ifdef EFL_BETA_API_SUPPORT
-/**
- * @struct _Efl_Network_Event_Url_Data
- * Used as the @p data param for the @ref EFL_NETWORK_EVENT_URL_DATA event
- * @ingroup Ecore_Con_Url_Group
- */
-struct _Efl_Network_Event_Url_Data
-{
-   Efl_Network_Url *url_con; /**< a pointer to the connection object */
-   int size; /**< the size of the current received data (in bytes) */
-   unsigned char *data; /**< pointer to the data received on this event */
-};
-#endif
-
 /**
  * @struct _Ecore_Con_Event_Url_Data
  * Used as the @p data param for the @ref ECORE_CON_EVENT_URL_DATA event
@@ -1745,6 +1717,26 @@ EAPI Eina_Bool         ecore_con_url_pipeline_get(void);
  * @see ecore_con_url_url_set()
  */
 EAPI Ecore_Con_Url *   ecore_con_url_new(const char *url);
+
+
+/**
+ * @brief Change the URL assigned to this handle.
+ *
+ * @param url_con Connection object to change URL.
+ * @param url the new URL.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on errors.
+ */
+EAPI Eina_Bool ecore_con_url_url_set(Ecore_Con_Url *url_con,
+                                     const char *url);
+
+/**
+ * @brief Retrieve the URL assigned to this handle.
+ *
+ * @param url_con the Connection object to retrieve URL.
+ * @return @c NULL on error, read-only URL string on success.
+ */
+EAPI const char *ecore_con_url_url_get(Ecore_Con_Url *url_con);
+
 /**
  * @brief Create a custom connection object.
  *
diff --git a/src/lib/ecore_con/Ecore_Con_Eo.h b/src/lib/ecore_con/Ecore_Con_Eo.h
index 931f2ed..e919d4c 100644
--- a/src/lib/ecore_con/Ecore_Con_Eo.h
+++ b/src/lib/ecore_con/Ecore_Con_Eo.h
@@ -2,7 +2,6 @@
 #include "efl_network_server.eo.h"
 #include "efl_network_connector.eo.h"
 #include "efl_network_client.eo.h"
-#include "efl_network_url.eo.h"
 
 #include "efl_net_socket.eo.h"
 #include "efl_net_dialer.eo.h"
diff --git a/src/lib/ecore_con/Ecore_Con_Legacy.h 
b/src/lib/ecore_con/Ecore_Con_Legacy.h
index a4041ad..1333eed 100644
--- a/src/lib/ecore_con/Ecore_Con_Legacy.h
+++ b/src/lib/ecore_con/Ecore_Con_Legacy.h
@@ -26,25 +26,4 @@ typedef Eo Ecore_Con_Client;
  *******************************************************************/
 typedef Eo Ecore_Con_Server;
 
-
-/********************************************************************
- * ecore_con_url.eo.h
- *******************************************************************/
-typedef Eo Ecore_Con_Url;
-
-
-/********************************************************************
- * ecore_con_url.eo.legacy.h
- *******************************************************************/
-/**
- * * Controls the URL to send the request to.
- * @param[in] url The URL
- */
-EAPI Eina_Bool ecore_con_url_url_set(Ecore_Con_Url *obj, const char *url);
-
-/**
- * * Controls the URL to send the request to.
- */
-EAPI const char *ecore_con_url_url_get(const Ecore_Con_Url *obj);
-
 #endif
diff --git a/src/lib/ecore_con/ecore_con_url.c 
b/src/lib/ecore_con/ecore_con_url.c
index dffbf42..ffe5bd5 100644
--- a/src/lib/ecore_con/ecore_con_url.c
+++ b/src/lib/ecore_con/ecore_con_url.c
@@ -16,14 +16,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
-
-#ifdef HAVE_WS2TCPIP_H
-# include <ws2tcpip.h>
-#endif
-
-#ifdef HAVE_ESCAPE
-# include <Escape.h>
-#endif
+#include <fcntl.h>
 
 #include "Ecore.h"
 #include "ecore_private.h"
@@ -32,78 +25,14 @@
 #include "ecore_con_url_curl.h"
 #include "Emile.h"
 
-#define MY_CLASS EFL_NETWORK_URL_CLASS
-
-
-typedef enum _Ecore_Con_Url_Mode
-{
-   ECORE_CON_URL_MODE_AUTO = 0,
-   ECORE_CON_URL_MODE_GET = 1,
-   ECORE_CON_URL_MODE_POST = 2,
-   ECORE_CON_URL_MODE_HEAD = 3,
-} Ecore_Con_Url_Mode;
-
-struct _Ecore_Con_Url_Data
-{
-   void *curl_easy;
-   struct curl_slist *headers;
-   Eina_List *additional_headers;
-   Eina_List *response_headers;
-   const char *url;
-   long proxy_type;
-   int status;
-
-   Ecore_Timer *timer;
-
-   Ecore_Con_Url_Time time_condition;
-   double timestamp;
-   void *data;
-   
-   void *post_data;
-
-   int received;
-   int write_fd;
-
-   unsigned int event_count;
-   Eina_Bool dead : 1;
-   Eina_Bool multi : 1;
-};
-
-typedef struct _Ecore_Con_Url_Data Ecore_Con_Url_Data;
-typedef struct _Ecore_Con_Url_Data Efl_Network_Url_Data;
-
 int ECORE_CON_EVENT_URL_DATA = 0;
 int ECORE_CON_EVENT_URL_COMPLETE = 0;
 int ECORE_CON_EVENT_URL_PROGRESS = 0;
 
-static void      _ecore_con_url_event_url_complete(Ecore_Con_Url *url_con, 
CURLMsg *curlmsg);
-static void      _ecore_con_url_multi_remove(Ecore_Con_Url *url_con);
-static Eina_Bool _ecore_con_url_perform(Ecore_Con_Url *url_con);
-static size_t    _ecore_con_url_header_cb(void *ptr, size_t size, size_t 
nitems, void *stream);
-static size_t    _ecore_con_url_data_cb(void *buffer, size_t size, size_t 
nitems, void *userp);
-static int       _ecore_con_url_progress_cb(void *clientp, double dltotal, 
double dlnow, double ultotal, double ulnow);
-static size_t    _ecore_con_url_read_cb(void *ptr, size_t size, size_t nitems, 
void *stream);
-static void      _ecore_con_event_url_free(Ecore_Con_Url *url_con, void *ev);
-static Eina_Bool _ecore_con_url_timer(void *data);
-static Eina_Bool _ecore_con_url_fd_handler(void *data, Ecore_Fd_Handler 
*fd_handler);
-static Eina_Bool _ecore_con_url_timeout_cb(void *data);
-static void      _ecore_con_url_status_get(Ecore_Con_Url *url_con);
-
-static Eina_List *_url_con_list = NULL;
-static Eina_List *_fd_hd_list = NULL;
 static int _init_count = 0;
-static Ecore_Timer *_curl_timer = NULL;
 static Eina_Bool pipelining = EINA_FALSE;
 
-static void
-_ecore_con_post_init(void)
-{
-   if (!_curl_timer)
-     {
-        _curl_timer = ecore_timer_add(_c_timeout, _ecore_con_url_timer, NULL);
-        ecore_timer_freeze(_curl_timer);
-     }
-}
+static Eina_List *_url_con_url_list = NULL;
 
 /**
  * @addtogroup Ecore_Con_Url_Group Ecore URL Connection Functions
@@ -116,6 +45,7 @@ ecore_con_url_init(void)
 {
    if (++_init_count > 1) return _init_count;
    if (!ecore_init()) goto ecore_init_failed;
+   if (!ecore_con_init()) goto ecore_con_init_failed;
    if (!emile_init()) goto emile_init_failed;
    if (!emile_cipher_init()) goto emile_cipher_init_failed;
    ECORE_CON_EVENT_URL_DATA = ecore_event_type_new();
@@ -126,6 +56,8 @@ ecore_con_url_init(void)
  emile_cipher_init_failed:
    emile_shutdown();
  emile_init_failed:
+   ecore_con_shutdown();
+ ecore_con_init_failed:
    ecore_shutdown();
  ecore_init_failed:
    return --_init_count;
@@ -134,22 +66,15 @@ ecore_con_url_init(void)
 EAPI int
 ecore_con_url_shutdown(void)
 {
-   Ecore_Con_Url *url_con;
-   Ecore_Fd_Handler *fd_handler;
+   Ecore_Con_Url *url_con_url;
    if (_init_count == 0) return 0;
    --_init_count;
    if (_init_count) return _init_count;
-   if (_curl_timer)
-     {
-        ecore_timer_del(_curl_timer);
-        _curl_timer = NULL;
-     }
-   EINA_LIST_FREE(_url_con_list, url_con)
-     ecore_con_url_free(url_con);
-   EINA_LIST_FREE(_fd_hd_list, fd_handler)
-     ecore_main_fd_handler_del(fd_handler);
+   EINA_LIST_FREE(_url_con_url_list, url_con_url)
+     ecore_con_url_free(url_con_url);
    _c_shutdown();
    emile_shutdown(); /* no emile_cipher_shutdown(), handled here */
+   ecore_con_shutdown();
    ecore_shutdown();
    return 0;
 }
@@ -158,7 +83,6 @@ EAPI void
 ecore_con_url_pipeline_set(Eina_Bool enable)
 {
    if (!_c_init()) return;
-   _ecore_con_post_init();
    if (enable == pipelining) return;
    _c->curl_multi_setopt(_c->_curlm, CURLMOPT_PIPELINING, !!enable);
    pipelining = enable;
@@ -170,1333 +94,1298 @@ ecore_con_url_pipeline_get(void)
    return pipelining;
 }
 
-extern Ecore_Con_Socks *_ecore_con_proxy_global;
+
+/* The rest of this file exists solely to provide ABI compatibility */
+
+struct _Ecore_Con_Url
+{
+   ECORE_MAGIC;
+   Eo *dialer;
+   Eo *send_copier;
+   Eo *input;
+   Ecore_Timer *timer;
+   struct {
+      Ecore_Animator *animator;
+      struct {
+         uint64_t total;
+         uint64_t now;
+      } download, upload;
+   } progress;
+   Eina_Stringshare *url;
+   Eina_Stringshare *custom_request;
+   void *data;
+   struct {
+      Eina_List *files; /* of Eina_Stringshare - read locations */
+      Eina_List *cmds; /* of static-const strings - COOKIELIST commands */
+      Eina_Stringshare *jar; /* write location */
+      Eina_Bool ignore_old_session;
+   } cookies;
+   struct {
+      Eina_Stringshare *url;
+      Eina_Stringshare *username;
+      Eina_Stringshare *password;
+   } proxy;
+   struct {
+      Ecore_Con_Url_Time condition;
+      double stamp;
+   } time;
+   struct {
+      Eina_Stringshare *username;
+      Eina_Stringshare *password;
+      Efl_Net_Http_Authentication_Method method;
+      Eina_Bool restricted;
+   } httpauth;
+   Eina_Stringshare *ca_path;
+   Eina_List *request_headers;
+   Eina_List *response_headers;
+   unsigned event_count;
+   int received_bytes;
+   int status;
+   int write_fd;
+   Efl_Net_Http_Version http_version;
+   Eina_Bool only_head;
+   Eina_Bool ssl_verify_peer;
+   Eina_Bool verbose;
+   Eina_Bool ftp_use_epsv;
+   Eina_Bool delete_me;
+};
+
+#define ECORE_CON_URL_CHECK_RETURN(u, ...) \
+  do \
+    { \
+       if (!ECORE_MAGIC_CHECK(u, ECORE_MAGIC_CON_URL)) \
+         { \
+            ECORE_MAGIC_FAIL(u, ECORE_MAGIC_CON_URL, __FUNCTION__); \
+            return __VA_ARGS__; \
+         } \
+       EINA_SAFETY_ON_TRUE_RETURN_VAL(u->delete_me, __VA_ARGS__); \
+    } \
+  while (0)
+
 
 static void
-_efl_network_url_event_complete_cb(void *data EINA_UNUSED, const Efl_Event 
*event)
+_ecore_con_url_dialer_close(Ecore_Con_Url *url_con)
 {
-   Ecore_Con_Event_Url_Complete *e, *f = event->info;
+   if (url_con->send_copier)
+     {
+        efl_del(url_con->send_copier);
+        url_con->send_copier = NULL;
+     }
 
-   e = calloc(1, sizeof(Ecore_Con_Event_Url_Complete));
-   if (!e)
+   if (url_con->input)
      {
-        efl_event_callback_stop(event->object);
-        return;
+        efl_del(url_con->input);
+        url_con->input = NULL;
+     }
+
+   if (url_con->timer)
+     {
+        ecore_timer_del(url_con->timer);
+        url_con->timer = NULL;
+     }
+
+   if (url_con->progress.animator)
+     {
+        ecore_animator_del(url_con->progress.animator);
+        url_con->progress.animator = NULL;
      }
 
-   e->status = f->status;
-   e->url_con = f->url_con;
-   ecore_event_add(ECORE_CON_EVENT_URL_COMPLETE, e,
-                   (Ecore_End_Cb)_ecore_con_event_url_free, event->object);
+   if (!url_con->dialer) return;
+
+   if (!efl_io_closer_closed_get(url_con->dialer))
+     efl_io_closer_close(url_con->dialer);
+   efl_del(url_con->dialer);
+   url_con->dialer = NULL;
+}
+
+static void
+_ecore_con_url_response_headers_free(Ecore_Con_Url *url_con)
+{
+   char *str;
+   EINA_LIST_FREE(url_con->response_headers, str)
+     free(str);
+}
 
-   efl_event_callback_stop(event->object);
+static void
+_ecore_con_url_request_headers_free(Ecore_Con_Url *url_con)
+{
+   Efl_Net_Http_Header *header;
+   EINA_LIST_FREE(url_con->response_headers, header)
+     free(header); /* key and value are inline */
 }
 
 static void
-_efl_network_url_event_data_cb(void *data EINA_UNUSED, const Efl_Event *event)
+_ecore_con_url_free_internal(Ecore_Con_Url *url_con)
 {
-   Ecore_Con_Event_Url_Data *e;
-   Efl_Network_Event_Url_Data *f = event->info;
+   const char *s;
+
+   url_con->delete_me = EINA_TRUE;
+   if (url_con->event_count > 0) return;
+
+   _ecore_con_url_dialer_close(url_con);
+
+   eina_stringshare_replace(&url_con->url, NULL);
+   eina_stringshare_replace(&url_con->custom_request, NULL);
+
+   url_con->data = NULL;
+
+   EINA_LIST_FREE(url_con->cookies.files, s)
+     eina_stringshare_del(s);
+   eina_list_free(url_con->cookies.cmds); /* data is not to be freed! */
+   eina_stringshare_replace(&url_con->cookies.jar, NULL);
+
+   eina_stringshare_replace(&url_con->proxy.url, NULL);
+   eina_stringshare_replace(&url_con->proxy.username, NULL);
+   eina_stringshare_replace(&url_con->proxy.password, NULL);
 
-   e = malloc(sizeof(Ecore_Con_Event_Url_Data) + sizeof(unsigned char) * 
f->size);
+   eina_stringshare_replace(&url_con->httpauth.username, NULL);
+   eina_stringshare_replace(&url_con->httpauth.password, NULL);
 
-   if (!e) return;
+   eina_stringshare_replace(&url_con->ca_path, NULL);
 
-   e->url_con = f->url_con;
-   e->size = f->size;
-   memcpy(e->data, f->data, f->size);
-   ecore_event_add(ECORE_CON_EVENT_URL_DATA, e,
-                   (Ecore_End_Cb)_ecore_con_event_url_free, event->object);
+   _ecore_con_url_request_headers_free(url_con);
+   _ecore_con_url_response_headers_free(url_con);
+
+   ECORE_MAGIC_SET(url_con, ECORE_MAGIC_NONE);
+   free(url_con);
 }
 
 static void
-_efl_network_url_event_progress_cb(void *data EINA_UNUSED, const Efl_Event 
*event)
+_ecore_con_event_url_progress_free(void *data EINA_UNUSED, void *event)
 {
-   Ecore_Con_Event_Url_Progress *e, *f = event->info;
-
-   e = malloc(sizeof(Ecore_Con_Event_Url_Progress));
-   if (!e) return;
-
-   e->url_con = f->url_con;
-   e->down.total = f->down.total;
-   e->down.now = f->down.now;
-   e->up.total = f->up.total;
-   e->up.now = f->up.now;
-   ecore_event_add(ECORE_CON_EVENT_URL_PROGRESS, e,
-                   (Ecore_End_Cb)_ecore_con_event_url_free, event->object);
-}
+   Ecore_Con_Event_Url_Progress *ev = event;
+   Ecore_Con_Url *url_con = ev->url_con;
 
-EFL_CALLBACKS_ARRAY_DEFINE(efl_network_url_event_table_callbacks,
-  { EFL_NETWORK_URL_EVENT_DATA, _efl_network_url_event_data_cb },
-  { EFL_NETWORK_URL_EVENT_PROGRESS, _efl_network_url_event_progress_cb },
-  { EFL_NETWORK_URL_EVENT_COMPLETE, _efl_network_url_event_complete_cb }
-);
+   EINA_SAFETY_ON_TRUE_GOTO(url_con->event_count == 0, end);
 
-EAPI Ecore_Con_Url *
-ecore_con_url_new(const char *url)
+   url_con->event_count--;
+   if ((url_con->event_count == 0) && (url_con->delete_me))
+     _ecore_con_url_free_internal(url_con);
+
+ end:
+   free(ev);
+}
+
+static void
+_ecore_con_event_url_progress_add(Ecore_Con_Url *url_con)
 {
-   Ecore_Con_Url *url_obj;
-   url_obj = efl_add(EFL_NETWORK_URL_CLASS, NULL, 
efl_network_url_set(efl_added, url));
+   Ecore_Con_Event_Url_Progress *ev;
 
-   efl_event_callback_array_add(url_obj, 
efl_network_url_event_table_callbacks(), NULL);
+   if (url_con->delete_me) return;
 
-   return url_obj;
+   ev = malloc(sizeof(*ev));
+   EINA_SAFETY_ON_NULL_RETURN(ev);
+
+   ev->url_con = url_con;
+   ev->down.total = url_con->progress.download.total;
+   ev->down.now = url_con->progress.download.now;
+   ev->up.total = url_con->progress.upload.total;
+   ev->up.now = url_con->progress.upload.now;
+   url_con->event_count++;
+   ecore_event_add(ECORE_CON_EVENT_URL_PROGRESS, ev, 
_ecore_con_event_url_progress_free, NULL);
 }
 
-EOLIAN static Eo *
-_efl_network_url_efl_object_constructor(Efl_Network_Url *url_obj, 
Efl_Network_Url_Data *url_con EINA_UNUSED)
+static void
+_ecore_con_event_url_complete_free(void *data EINA_UNUSED, void *event)
 {
-   url_obj = efl_constructor(efl_super(url_obj, MY_CLASS));
-
-   if (!_init_count || !_c_init())
-     {
-        ERR("Failed");
-        return NULL;
-     }
-   _ecore_con_post_init();
+   Ecore_Con_Event_Url_Complete *ev = event;
+   Ecore_Con_Url *url_con = ev->url_con;
 
-   url_con->curl_easy = _c->curl_easy_init();
-   if (!url_con->curl_easy)
-     {
-        ERR("Failed");
-        return NULL;
-     }
+   EINA_SAFETY_ON_TRUE_GOTO(url_con->event_count == 0, end);
 
-   efl_manual_free_set(url_obj, EINA_TRUE);
+   url_con->event_count--;
+   if ((url_con->event_count == 0) && (url_con->delete_me))
+     _ecore_con_url_free_internal(url_con);
 
-   return url_obj;
+ end:
+   free(ev);
 }
 
-EOLIAN static Eo *
-_efl_network_url_efl_object_finalize(Efl_Network_Url *url_obj, 
Efl_Network_Url_Data *url_con)
+static void
+_ecore_con_event_url_complete_add(Ecore_Con_Url *url_con, int status)
 {
-   CURLcode ret;
+   Ecore_Con_Event_Url_Complete *ev;
 
-   url_con->write_fd = -1;
+   if (url_con->delete_me) return;
 
-   if (!url_con->url)
+   if (url_con->progress.animator)
      {
-        return NULL;
+        ecore_animator_del(url_con->progress.animator);
+        url_con->progress.animator = NULL;
+        _ecore_con_event_url_progress_add(url_con);
      }
 
-   // Read socks proxy
-   url_con->proxy_type = -1;
-   if (_ecore_con_proxy_global && _ecore_con_proxy_global->ip &&
-       ((_ecore_con_proxy_global->version == 4) ||
-        (_ecore_con_proxy_global->version == 5)))
+   if (url_con->status)
      {
-        char proxy[256];
-        char host[256];
-
-        if (_ecore_con_proxy_global->version == 5)
-          {
-             if (_ecore_con_proxy_global->lookup)
-               snprintf(host, sizeof(host), "socks5h://%s",
-                        _ecore_con_proxy_global->ip);
-             else
-               snprintf(host, sizeof(host), "socks5://%s",
-                        _ecore_con_proxy_global->ip);
-          }
-        else if (_ecore_con_proxy_global->version == 4)
-          {
-             if (_ecore_con_proxy_global->lookup)
-               snprintf(host, sizeof(host), "socks4a://%s",
-                        _ecore_con_proxy_global->ip);
-             else
-               snprintf(host, sizeof(host), "socks4://%s",
-                        _ecore_con_proxy_global->ip);
-          }
+        DBG("URL '%s' was already complete with status=%d, new=%d", 
url_con->url, url_con->status, status);
+        goto end;
+     }
 
-        if (_ecore_con_proxy_global->port > 0 &&
-            _ecore_con_proxy_global->port <= 65535)
-          snprintf(proxy, sizeof(proxy), "%s:%d", host,
-                   _ecore_con_proxy_global->port);
-        else snprintf(proxy, sizeof(proxy), "%s", host);
+   url_con->status = status;
 
-        ecore_con_url_proxy_set(url_obj, proxy);
-        ecore_con_url_proxy_username_set(url_obj,
-                                         _ecore_con_proxy_global->username);
-     }
+   ev = malloc(sizeof(Ecore_Con_Event_Url_Complete));
+   EINA_SAFETY_ON_NULL_GOTO(ev, end);
 
-   ret = _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_ENCODING,
-                              "gzip,deflate");
-   if (ret != CURLE_OK)
-     {
-        ERR("Could not set CURLOPT_ENCODING to \"gzip,deflate\": %s",
-            _c->curl_easy_strerror(ret));
-        ecore_con_url_free(url_obj);
-        return NULL;
-     }
+   ev->url_con = url_con;
+   ev->status = status;
+   url_con->event_count++;
+   ecore_event_add(ECORE_CON_EVENT_URL_COMPLETE, ev, 
_ecore_con_event_url_complete_free, NULL);
 
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_WRITEFUNCTION,
-                        _ecore_con_url_data_cb);
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_WRITEDATA, url_obj);
-
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_PROGRESSFUNCTION,
-                        _ecore_con_url_progress_cb);
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_PROGRESSDATA, url_obj);
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_NOPROGRESS, EINA_FALSE);
-
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_HEADERFUNCTION,
-                        _ecore_con_url_header_cb);
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_HEADERDATA, url_obj);
-   /*
-    * FIXME: Check that these timeouts are sensible defaults
-    * FIXME: Provide a means to change these timeouts
-    */
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_CONNECTTIMEOUT, 30);
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_FOLLOWLOCATION, 1);
-   return efl_finalize(efl_super(url_obj, MY_CLASS));
+ end:
+   _ecore_con_url_dialer_close(url_con);
 }
 
-EAPI Ecore_Con_Url *
-ecore_con_url_custom_new(const char *url,
-                         const char *custom_request)
+static void
+_ecore_con_url_dialer_error(void *data, const Efl_Event *event)
 {
-   Ecore_Con_Url *url_obj;
-   CURLcode ret;
-
-   if (!_init_count) return NULL;
-   if (!_c_init()) return NULL;
-   _ecore_con_post_init();
-   if (!url) return NULL;
-   if (!custom_request) return NULL;
-   url_obj = ecore_con_url_new(url);
-   if (!url_obj) return NULL;
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-
-   ret = _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_CUSTOMREQUEST,
-                              custom_request);
-   if (ret != CURLE_OK)
+   Ecore_Con_Url *url_con = data;
+   Eina_Error *perr = event->info;
+   int status;
+
+   status = efl_net_dialer_http_response_status_get(url_con->dialer);
+   if ((status < 500) && (status > 599))
      {
-        ERR("Could not set a custom request string: %s",
-            _c->curl_easy_strerror(ret));
-        ecore_con_url_free(url_obj);
-        return NULL;
+        DBG("HTTP error %d reset to 1", status);
+        status = 1; /* not a real HTTP error */
      }
-   return url_obj;
-}
 
-EAPI void
-ecore_con_url_free(Ecore_Con_Url *url_obj)
-{
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return;
+   WRN("HTTP dialer error url='%s': %s",
+       efl_net_dialer_address_dial_get(url_con->dialer),
+       eina_error_msg_get(*perr));
 
-   efl_event_callback_array_del(url_obj, 
efl_network_url_event_table_callbacks(), NULL);
-
-   efl_del(url_obj);
+   _ecore_con_event_url_complete_add(url_con, status);
 }
 
 static void
-_ecore_con_url_free_internal(Ecore_Con_Url *url_obj)
+_ecore_con_event_url_data_free(void *data EINA_UNUSED, void *event)
 {
-   Efl_Network_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   char *s;
+   Ecore_Con_Event_Url_Data *ev = event;
+   Ecore_Con_Url *url_con = ev->url_con;
 
-   if (_c) _c->curl_slist_free_all(url_con->headers);
-   EINA_LIST_FREE(url_con->additional_headers, s)
-     free(s);
-   EINA_LIST_FREE(url_con->response_headers, s)
-     free(s);
-   eina_stringshare_del(url_con->url);
-   if (url_con->post_data) free(url_con->post_data);
+   EINA_SAFETY_ON_TRUE_GOTO(url_con->event_count == 0, end);
+
+   url_con->event_count--;
+   if ((url_con->event_count == 0) && (url_con->delete_me))
+     _ecore_con_url_free_internal(url_con);
+
+ end:
+   free(ev);
 }
 
-EOLIAN static void
-_efl_network_url_efl_object_destructor(Efl_Network_Url *url_obj, 
Efl_Network_Url_Data *url_con)
+static void
+_ecore_con_url_dialer_can_read_changed(void *data, const Efl_Event *event 
EINA_UNUSED)
 {
-   efl_destructor(efl_super(url_obj, MY_CLASS));
-
-   if (!_c) return;
-   if (url_con->curl_easy)
-     {
-        // FIXME : How can we delete curl_easy's fds ??
-        // (Curl do not give this info.)
-        // This cause "Failed to delete epoll fd xx!" error messages
-        _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_PROGRESSFUNCTION,
-                             NULL);
-        _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_NOPROGRESS,
-                             EINA_TRUE);
-
-        if (url_con->multi)
-          {
-             _ecore_con_url_multi_remove(url_obj);
-             _url_con_list = eina_list_remove(_url_con_list, url_obj);
-          }
+   Ecore_Con_Url *url_con = data;
+   Eina_Bool can_read;
+   Ecore_Con_Event_Url_Data *ev;
+   Eina_Rw_Slice slice;
+   Eina_Error err;
 
-        _c->curl_easy_cleanup(url_con->curl_easy);
-     }
-   if (url_con->timer) ecore_timer_del(url_con->timer);
+   if (url_con->delete_me) return;
 
-   url_con->curl_easy = NULL;
-   url_con->timer = NULL;
-   url_con->dead = EINA_TRUE;
-   if (url_con->event_count) return;
+   can_read = efl_io_reader_can_read_get(url_con->dialer);
+   if (!can_read) return;
 
-   efl_manual_free_set(url_obj, EINA_FALSE);
-   _ecore_con_url_free_internal(url_obj);
-}
+   ev = malloc(sizeof(Ecore_Con_Event_Url_Data) + 
EFL_NET_DIALER_HTTP_BUFFER_RECEIVE_SIZE);
+   EINA_SAFETY_ON_NULL_RETURN(ev);
 
-EOLIAN static const char *
-_efl_network_url_url_get(Efl_Network_Url *url_obj EINA_UNUSED, 
Efl_Network_Url_Data *url_con)
-{
-   return url_con->url;
-}
+   slice.mem = ev->data;
+   slice.len = EFL_NET_DIALER_HTTP_BUFFER_RECEIVE_SIZE;
 
-EAPI int
-ecore_con_url_status_code_get(Ecore_Con_Url *url_obj)
-{
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return 0;
-   if (url_con->status) return url_con->status;
-   _ecore_con_url_status_get(url_obj);
-   return url_con->status;
-}
+   err = efl_io_reader_read(url_con->dialer, &slice);
+   if (err)
+     {
+        free(ev);
+        if (err == EAGAIN) return;
+        WRN("Error reading data from HTTP url='%s': %s",
+            efl_net_dialer_address_dial_get(url_con->dialer),
+            eina_error_msg_get(err));
+        return;
+     }
 
-EOLIAN static Eina_Bool
-_efl_network_url_url_set(Efl_Network_Url *url_obj EINA_UNUSED, 
Efl_Network_Url_Data *url_con, const char *url)
-{
-   if (!_c) return EINA_FALSE;
-   if (url_con->dead) return EINA_FALSE;
-   eina_stringshare_replace(&url_con->url, url);
-   if (url_con->url)
-     _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_URL,
-                          url_con->url);
-   else
-     _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_URL, "");
-   return EINA_TRUE;
-}
+   ev->size = slice.len;
+   ev->url_con = url_con;
+   url_con->received_bytes += ev->size;
 
-EAPI void
-ecore_con_url_data_set(Ecore_Con_Url *url_obj, void *data)
-{
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return;
-   url_con->data = data;
-}
+   if (url_con->write_fd == -1)
+     {
+        url_con->event_count++;
+        ecore_event_add(ECORE_CON_EVENT_URL_DATA, ev, 
_ecore_con_event_url_data_free, NULL);
+        return;
+     }
 
-EAPI void
-ecore_con_url_additional_header_add(Ecore_Con_Url *url_obj, const char *key, 
const char *value)
-{
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return;
-   char *tmp;
-
-   if (url_con->dead) return;
-   tmp = malloc(strlen(key) + strlen(value) + 3);
-   if (!tmp) return;
-   sprintf(tmp, "%s: %s", key, value);
-   url_con->additional_headers = eina_list_append(url_con->additional_headers,
-                                                  tmp);
+   while (slice.len > 0)
+     {
+        ssize_t r = write(url_con->write_fd, slice.bytes, slice.len);
+        if (r == -1)
+          {
+             ERR("Could not write to fd=%d: %s", url_con->write_fd, 
strerror(errno));
+             break;
+          }
+        slice.bytes += r;
+        slice.len -= r;
+     }
+   free(ev);
 }
 
-EAPI void
-ecore_con_url_additional_headers_clear(Ecore_Con_Url *url_obj)
+static void
+_ecore_con_url_dialer_eos(void *data, const Efl_Event *event EINA_UNUSED)
 {
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return;
-   char *s;
+   Ecore_Con_Url *url_con = data;
 
-   EINA_LIST_FREE(url_con->additional_headers, s)
-     free(s);
-}
+   DBG("HTTP EOS url='%s'", efl_net_dialer_address_dial_get(url_con->dialer));
 
-EAPI void *
-ecore_con_url_data_get(Ecore_Con_Url *url_obj)
-{
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return NULL;
-   return url_con->data;
-}
+   if (url_con->send_copier && (!efl_io_copier_done_get(url_con->send_copier)))
+     {
+        DBG("done receiving, waiting for send copier...");
+        return;
+     }
 
-EAPI void
-ecore_con_url_time(Ecore_Con_Url *url_obj, Ecore_Con_Url_Time condition, 
double timestamp)
-{
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return;
-   if (url_con->dead) return;
-   url_con->time_condition = condition;
-   url_con->timestamp = timestamp;
+   _ecore_con_event_url_complete_add(url_con, 
efl_net_dialer_http_response_status_get(url_con->dialer));
 }
 
-EAPI void
-ecore_con_url_fd_set(Ecore_Con_Url *url_obj, int fd)
+static void
+_ecore_con_url_dialer_headers_done(void *data, const Efl_Event *event 
EINA_UNUSED)
 {
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return;
-   if (url_con->dead) return;
-   url_con->write_fd = fd;
-}
+   Ecore_Con_Url *url_con = data;
+   Eina_Iterator *it;
+   Efl_Net_Http_Header *header;
+   size_t len;
+   char *str;
 
-EAPI int
-ecore_con_url_received_bytes_get(Ecore_Con_Url *url_obj)
-{
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return -1;
-   return url_con->received;
-}
+   DBG("HTTP headers done, status=%d url='%s'",
+       efl_net_dialer_http_response_status_get(url_con->dialer),
+       efl_net_dialer_address_dial_get(url_con->dialer));
 
-EAPI const Eina_List *
-ecore_con_url_response_headers_get(Ecore_Con_Url *url_obj)
-{
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return NULL;
-   return url_con->response_headers;
-}
+   _ecore_con_url_response_headers_free(url_con);
 
-EAPI Eina_Bool
-ecore_con_url_httpauth_set(Ecore_Con_Url *url_obj, const char *username, const 
char *password, Eina_Bool safe)
-{
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return EINA_FALSE;
-   CURLcode ret;
-   curl_version_info_data *vers = NULL;
-
-   if (!_c) return EINA_FALSE;
-   if (url_con->dead) return EINA_FALSE;
-   vers = _c->curl_version_info(CURLVERSION_NOW);
-   if (vers->version_num >= 0x071301)
+   it = efl_net_dialer_http_response_headers_all_get(url_con->dialer);
+   EINA_SAFETY_ON_NULL_RETURN(it);
+   EINA_ITERATOR_FOREACH(it, header)
      {
-        if ((username) && (password))
+        if (header->key)
+          {
+             len = strlen(header->key) + strlen(header->value) + strlen(": 
\r\n") + 1;
+             str = malloc(len);
+             EINA_SAFETY_ON_NULL_GOTO(str, end);
+             snprintf(str, len, "%s: %s\r\n", header->key, header->value);
+             url_con->response_headers = 
eina_list_append(url_con->response_headers, str);
+          }
+        else
           {
-             if (safe)
-               _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_HTTPAUTH,
-                                    CURLAUTH_ANYSAFE);
-             else
-               _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_HTTPAUTH,
-                                    CURLAUTH_ANY);
-
-             ret = _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_USERNAME,
-                                        username);
-             if (ret != CURLE_OK)
+             if (url_con->response_headers)
                {
-                  ERR("Could not set username for HTTP authentication: %s",
-                      _c->curl_easy_strerror(ret));
-                  return EINA_FALSE;
+                  str = malloc(strlen("\r\n") + 1);
+                  EINA_SAFETY_ON_NULL_GOTO(str, end);
+                  memcpy(str, "\r\n", strlen("\r\n") + 1);
+                  url_con->response_headers = 
eina_list_append(url_con->response_headers, str);
                }
 
-             ret = _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_PASSWORD,
-                                        password);
-             if (ret != CURLE_OK)
-               {
-                  ERR("Could not set password for HTTP authentication: %s",
-                      _c->curl_easy_strerror(ret));
-                  return EINA_FALSE;
-               }
-             return EINA_TRUE;
+             len = strlen(header->value) + strlen("\r\n") + 1;
+             str = malloc(len);
+             EINA_SAFETY_ON_NULL_GOTO(str, end);
+             snprintf(str, len, "%s\r\n", header->value);
+             url_con->response_headers = 
eina_list_append(url_con->response_headers, str);
           }
      }
-   return EINA_FALSE;
+
+   str = malloc(strlen("\r\n") + 1);
+   EINA_SAFETY_ON_NULL_GOTO(str, end);
+   memcpy(str, "\r\n", strlen("\r\n") + 1);
+   url_con->response_headers = eina_list_append(url_con->response_headers, 
str);
+
+ end:
+   eina_iterator_free(it);
+
+   if (url_con->only_head)
+     _ecore_con_url_dialer_close(url_con);
 }
 
+EFL_CALLBACKS_ARRAY_DEFINE(ecore_con_url_dialer_cbs,
+                           { EFL_IO_READER_EVENT_CAN_READ_CHANGED, 
_ecore_con_url_dialer_can_read_changed },
+                           { EFL_IO_READER_EVENT_EOS, 
_ecore_con_url_dialer_eos },
+                           { EFL_NET_DIALER_EVENT_ERROR, 
_ecore_con_url_dialer_error },
+                           { EFL_NET_DIALER_HTTP_EVENT_HEADERS_DONE, 
_ecore_con_url_dialer_headers_done });
 
 static Eina_Bool
-_ecore_con_url_send(Ecore_Con_Url *url_obj, Ecore_Con_Url_Mode mode,
-                    const void *data, long length, const char *content_type)
+_ecore_con_url_progress_animator_cb(void *data)
 {
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return EINA_FALSE;
-   Eina_List *l;
-   const char *s;
-   char tmp[512];
+   Ecore_Con_Url *url_con = data;
+   uint64_t dn, dt, un, ut;
 
-   if (!_c) return EINA_FALSE;
+   efl_net_dialer_http_progress_download_get(url_con->dialer, &dn, &dt);
+   efl_net_dialer_http_progress_upload_get(url_con->dialer, &un, &ut);
 
-   if (!url_con->url) return EINA_FALSE;
-   if (url_con->dead) return EINA_FALSE;
+   if ((dn == url_con->progress.download.now) &&
+       (dt == url_con->progress.download.total) &&
+       (un == url_con->progress.upload.now) &&
+       (ut == url_con->progress.upload.total))
+     return EINA_TRUE;
 
-   /* Free response headers from previous send() calls */
-   EINA_LIST_FREE(url_con->response_headers, s)
-     free((char *)s);
-   url_con->response_headers = NULL;
-   url_con->status = 0;
+   url_con->progress.download.now = dn;
+   url_con->progress.download.total = dt;
+   url_con->progress.upload.now = un;
+   url_con->progress.upload.total = ut;
+
+   _ecore_con_event_url_progress_add(url_con);
+
+   return EINA_TRUE;
+}
+
+/*
+ * creates a new efl_net_dialer_proxy_set() URL based on legacy parameters:
+ *  - proxy url (that could contain user + pass encoded, optional protocol)
+ *    - no protocol = http://
+ *  - username
+ *  - password
+ *
+ * May return NULL (= use envvar http_proxy)
+ */
+static char *
+_ecore_con_url_proxy_url_new(const Ecore_Con_Url *url_con)
+{
+   Eina_Slice protocol, user = {}, pass = {}, address;
+   char buf[4096];
+   const char *p;
 
-   _c->curl_slist_free_all(url_con->headers);
-   url_con->headers = NULL;
-   if ((mode == ECORE_CON_URL_MODE_POST) || (mode == ECORE_CON_URL_MODE_AUTO))
+   if (!url_con->proxy.url) return NULL; /* use from envvar */
+
+   p = strstr(url_con->proxy.url, "://");
+   if (!p)
+     {
+        protocol = (Eina_Slice)EINA_SLICE_STR_LITERAL("http");
+        address = (Eina_Slice)EINA_SLICE_STR(url_con->proxy.url);
+     }
+   else
      {
-        if (url_con->post_data) free(url_con->post_data);
-        url_con->post_data = NULL;
-        if ((data) && (length > 0))
+        const char *s;
+
+        protocol.mem = url_con->proxy.url;
+        protocol.len = p - url_con->proxy.url;
+        if (protocol.len == 0)
+          protocol = (Eina_Slice)EINA_SLICE_STR_LITERAL("http");
+
+        p += strlen("://");
+        s = strchr(p, '@');
+        if (!s)
           {
-             url_con->post_data = malloc(length);
-             if (url_con->post_data)
+             address = (Eina_Slice)EINA_SLICE_STR(p);
+          }
+        else
+          {
+             address = (Eina_Slice)EINA_SLICE_STR(s + 1);
+
+             user.mem = p;
+             user.len = s - p;
+
+             s = eina_slice_strchr(user, ':');
+             if (s)
                {
-                  memcpy(url_con->post_data, data, length);
-                  if ((content_type) && (strlen(content_type) < 450))
-                    {
-                       snprintf(tmp, sizeof(tmp), "Content-Type: %s",
-                                content_type);
-                       url_con->headers =
-                         _c->curl_slist_append(url_con->headers, tmp);
-                    }
-                  _c->curl_easy_setopt(url_con->curl_easy,
-                                       CURLOPT_POSTFIELDS, url_con->post_data);
-                  _c->curl_easy_setopt(url_con->curl_easy,
-                                       CURLOPT_POSTFIELDSIZE, length);
+                  pass.mem = s + 1;
+                  pass.len = user.len - (user.bytes - pass.bytes);
+                  user.len = s - (const char *)user.bytes;
                }
-             else
-               return EINA_FALSE;
           }
-        else
-          _c->curl_easy_setopt(url_con->curl_easy,
-                               CURLOPT_POSTFIELDSIZE, 0);
-        if (mode == ECORE_CON_URL_MODE_POST)
-          _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_POST, 1);
      }
-   else if (mode == ECORE_CON_URL_MODE_HEAD)
-     _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_NOBODY, 1L);
 
-   switch (url_con->time_condition)
+   if (url_con->proxy.username)
+     user = eina_stringshare_slice_get(url_con->proxy.username);
+
+   if (url_con->proxy.password)
+     pass = eina_stringshare_slice_get(url_con->proxy.password);
+
+   if (user.len && pass.len)
      {
-      case ECORE_CON_URL_TIME_NONE:
-        _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMECONDITION,
-                             CURL_TIMECOND_NONE);
-        break;
-
-      case ECORE_CON_URL_TIME_IFMODSINCE:
-        _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMECONDITION,
-                             CURL_TIMECOND_IFMODSINCE);
-        _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMEVALUE,
-                             (long)url_con->timestamp);
-        break;
-
-      case ECORE_CON_URL_TIME_IFUNMODSINCE:
-        _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMECONDITION,
-                             CURL_TIMECOND_IFUNMODSINCE);
-        _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMEVALUE,
-                             (long)url_con->timestamp);
-        break;
+        snprintf(buf, sizeof(buf),
+                 EINA_SLICE_STR_FMT "://"
+                 EINA_SLICE_STR_FMT ":"
+                 EINA_SLICE_STR_FMT "@"
+                 EINA_SLICE_STR_FMT,
+                 EINA_SLICE_STR_PRINT(protocol),
+                 EINA_SLICE_STR_PRINT(user),
+                 EINA_SLICE_STR_PRINT(pass),
+                 EINA_SLICE_STR_PRINT(address));
+     }
+   else if (user.len)
+     {
+        snprintf(buf, sizeof(buf),
+                 EINA_SLICE_STR_FMT "://"
+                 EINA_SLICE_STR_FMT "@"
+                 EINA_SLICE_STR_FMT,
+                 EINA_SLICE_STR_PRINT(protocol),
+                 EINA_SLICE_STR_PRINT(user),
+                 EINA_SLICE_STR_PRINT(address));
+     }
+   else
+     {
+        snprintf(buf, sizeof(buf),
+                 EINA_SLICE_STR_FMT "://" EINA_SLICE_STR_FMT,
+                 EINA_SLICE_STR_PRINT(protocol),
+                 EINA_SLICE_STR_PRINT(address));
      }
-   /* Additional headers */
-   EINA_LIST_FOREACH(url_con->additional_headers, l, s)
-     url_con->headers = _c->curl_slist_append(url_con->headers, s);
-
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_HTTPHEADER,
-                        url_con->headers);
-   url_con->received = 0;
-   return _ecore_con_url_perform(url_obj);
-}
 
-EAPI Eina_Bool
-ecore_con_url_get(Ecore_Con_Url *url_con)
-{
-   return _ecore_con_url_send(url_con, ECORE_CON_URL_MODE_GET, NULL, 0, NULL);
+   return strdup(buf);
 }
 
-EAPI Eina_Bool
-ecore_con_url_head(Ecore_Con_Url *url_con)
+static void
+_ecore_con_url_copier_done(void *data, const Efl_Event *event)
 {
-   return _ecore_con_url_send(url_con, ECORE_CON_URL_MODE_HEAD, NULL, 0, NULL);
-}
+   Ecore_Con_Url *url_con = data;
+   int status = efl_net_dialer_http_response_status_get(url_con->dialer);
 
-EAPI Eina_Bool
-ecore_con_url_post(Ecore_Con_Url *url_con, const void *data, long length, 
const char *content_type)
-{
-   return _ecore_con_url_send(url_con, ECORE_CON_URL_MODE_POST, data, length, 
content_type);
-}
+   DBG("copier %s %p for url='%s' is done", efl_name_get(event->object), 
event->object, efl_net_dialer_address_dial_get(url_con->dialer));
 
-EAPI Eina_Bool
-ecore_con_url_ftp_upload(Ecore_Con_Url *url_obj, const char *filename, const 
char *user, const char *pass, const char *upload_dir)
-{
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, MY_CLASS))
-      return EINA_FALSE;
-   char url[4096];
-   char userpwd[4096];
-   FILE *fd;
-   struct stat file_info;
-   CURLcode ret;
-
-   if (!_c) return EINA_FALSE;
-
-   if (url_con->dead) return EINA_FALSE;
-   if (!url_con->url) return EINA_FALSE;
-   if ((!filename) || (!filename[0])) return EINA_FALSE;
-
-   if (stat(filename, &file_info)) return EINA_FALSE;
-
-   snprintf(userpwd, sizeof(userpwd), "%s:%s", user, pass);
-   ret = _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_USERPWD, userpwd);
-   if (ret != CURLE_OK)
+   if (!efl_io_reader_eos_get(url_con->dialer))
      {
-        ERR("Could not set username and password for FTP upload: %s",
-            _c->curl_easy_strerror(ret));
-        return EINA_FALSE;
+        DBG("done sending, waiting for dialer EOS...");
+        return;
      }
 
-   char tmp[PATH_MAX];
-   snprintf(tmp, PATH_MAX, "%s", filename);
+   _ecore_con_event_url_complete_add(url_con, status);
+}
 
-   if (upload_dir)
-     snprintf(url, sizeof(url), "%s/%s/%s", url_con->url,
-              upload_dir, basename(tmp));
-   else
-     snprintf(url, sizeof(url), "%s/%s", url_con->url,
-              basename(tmp));
+static void
+_ecore_con_url_copier_error(void *data, const Efl_Event *event)
+{
+   Ecore_Con_Url *url_con = data;
+   Eina_Error *perr = event->info;
+   int status;
 
-   if (!ecore_con_url_url_set(url_obj, url))
-     return EINA_FALSE;
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_INFILESIZE_LARGE,
-                        (off_t)file_info.st_size);
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_UPLOAD, 1);
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_READFUNCTION,
-                        _ecore_con_url_read_cb);
-   fd = fopen(filename, "rb");
-   if (!fd)
+   status = efl_net_dialer_http_response_status_get(url_con->dialer);
+   if ((status < 500) && (status > 599))
      {
-        ERR("Could not open \"%s\" for FTP upload", filename);
-        return EINA_FALSE;
+        DBG("HTTP error %d reset to 1", status);
+        status = 1; /* not a real HTTP error */
      }
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_READDATA, fd);
-   return _ecore_con_url_perform(url_obj);
-}
 
-EAPI void
-ecore_con_url_cookies_init(Ecore_Con_Url *url_obj)
-{
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return;
-   if (!_c) return;
-   if (url_con->dead) return;
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIEFILE, "");
-}
+   WRN("HTTP copier %s %p error url='%s': %s",
+       efl_name_get(event->object), event->object,
+       efl_net_dialer_address_dial_get(url_con->dialer),
+       eina_error_msg_get(*perr));
 
-EAPI void
-ecore_con_url_cookies_ignore_old_session_set(Ecore_Con_Url *url_obj, Eina_Bool 
ignore)
-{
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return;
-   if (!_c) return;
-   if (url_con->dead) return;
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIESESSION, ignore);
+   _ecore_con_event_url_complete_add(url_con, status);
 }
 
-EAPI void
-ecore_con_url_cookies_clear(Ecore_Con_Url *url_obj)
-{
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return;
-   if (!_c) return;
-   if (url_con->dead) return;
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIELIST, "ALL");
-}
+EFL_CALLBACKS_ARRAY_DEFINE(_ecore_con_url_copier_cbs,
+                           { EFL_IO_COPIER_EVENT_ERROR, 
_ecore_con_url_copier_error },
+                           { EFL_IO_COPIER_EVENT_DONE, 
_ecore_con_url_copier_done });
 
-EAPI void
-ecore_con_url_cookies_session_clear(Ecore_Con_Url *url_obj)
+/*
+ * Ecore_Con_Url is documented as 'reusable', while Efl.Net.Dialers
+ * are one-shot and must be recreated on every usage.
+ *
+ * Then _ecore_con_url_request_prepare() will close (cancel) any
+ * previous dialer and create a new one with all parameters set.
+ */
+static Eina_Bool
+_ecore_con_url_request_prepare(Ecore_Con_Url *url_con, const char *method)
 {
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return;
-   if (!_c) return;
-   if (url_con->dead) return;
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIELIST, "SESS");
-}
+   const Efl_Net_Http_Header *header;
+   const Eina_List *n;
+   const char *s;
+   char *proxy_url = NULL;
+   CURL *curl_easy;
 
-EAPI void
-ecore_con_url_cookies_file_add(Ecore_Con_Url *url_obj, const char *const 
file_name)
-{
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return;
-   if (!_c) return;
-   if (url_con->dead) return;
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIEFILE, file_name);
-}
+   _ecore_con_url_dialer_close(url_con);
 
-EAPI Eina_Bool
-ecore_con_url_cookies_jar_file_set(Ecore_Con_Url *url_obj, const char *const 
cookiejar_file)
-{
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return EINA_FALSE;
-   CURLcode ret;
-
-   if (!_c) return EINA_FALSE;
-   if (url_con->dead) return EINA_FALSE;
-   ret = _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIEJAR,
-                              cookiejar_file);
-   if (ret != CURLE_OK)
+   url_con->status = 0;
+   url_con->received_bytes = 0;
+   url_con->progress.download.now = 0;
+   url_con->progress.download.total = 0;
+   url_con->progress.upload.now = 0;
+   url_con->progress.upload.total = 0;
+   _ecore_con_url_response_headers_free(url_con);
+
+   proxy_url = _ecore_con_url_proxy_url_new(url_con);
+   if (proxy_url)
+     DBG("proxy_url='%s'", proxy_url);
+
+   url_con->dialer = efl_add(EFL_NET_DIALER_HTTP_CLASS, ecore_main_loop_get(),
+                             efl_net_dialer_http_method_set(efl_added, 
url_con->custom_request ? url_con->custom_request : method),
+                             efl_net_dialer_http_primary_mode_set(efl_added, 
(strcmp(method, "PUT") == 0) ? EFL_NET_DIALER_HTTP_PRIMARY_MODE_UPLOAD : 
EFL_NET_DIALER_HTTP_PRIMARY_MODE_DOWNLOAD),
+                             efl_net_dialer_proxy_set(efl_added, proxy_url),
+                             efl_net_dialer_http_authentication_set(efl_added, 
url_con->httpauth.username, url_con->httpauth.password, 
url_con->httpauth.method, url_con->httpauth.restricted),
+                             efl_net_dialer_http_version_set(efl_added, 
url_con->http_version),
+                             
efl_net_dialer_http_allow_redirects_set(efl_added, EINA_TRUE),
+                             efl_net_dialer_http_ssl_verify_set(efl_added, 
url_con->ssl_verify_peer, url_con->ssl_verify_peer),
+                             
efl_net_dialer_http_ssl_certificate_authority_set(efl_added, url_con->ca_path),
+                             efl_event_callback_array_add(efl_added, 
ecore_con_url_dialer_cbs(), url_con));
+   EINA_SAFETY_ON_NULL_GOTO(url_con->dialer, error);
+
+   curl_easy = efl_net_dialer_http_curl_get(url_con->dialer);
+   EINA_SAFETY_ON_NULL_GOTO(curl_easy, error_curl_easy);
+
+   if (url_con->verbose)
      {
-        ERR("Setting the cookie-jar name failed: %s",
-            _c->curl_easy_strerror(ret));
-        return EINA_FALSE;
+        _c->curl_easy_setopt(curl_easy, CURLOPT_DEBUGFUNCTION, NULL);
+        _c->curl_easy_setopt(curl_easy, CURLOPT_DEBUGDATA, NULL);
+        _c->curl_easy_setopt(curl_easy, CURLOPT_VERBOSE, 1L);
+        DBG("HTTP Dialer %p is set to legacy debug function (CURL's default, 
no eina_log)", url_con->dialer);
      }
+
+   _c->curl_easy_setopt(curl_easy, CURLOPT_FTP_USE_EPSV, 
(long)url_con->ftp_use_epsv);
+
+   url_con->only_head = strcmp(method, "HEAD") == 0;
+
+   /* previously always set encoding to gzip,deflate */
+   efl_net_dialer_http_request_header_add(url_con->dialer, "Accept-Encoding", 
"gzip,deflate");
+
+   if (url_con->time.condition != ECORE_CON_URL_TIME_NONE)
+     {
+        char *ts = 
efl_net_dialer_http_date_serialize(EFL_NET_DIALER_HTTP_CLASS, 
url_con->time.stamp);
+        if (ts)
+          {
+             efl_net_dialer_http_request_header_add(url_con->dialer,
+                                                    url_con->time.condition == 
ECORE_CON_URL_TIME_IFMODSINCE ? "If-Modified-Since" : "If-Unmodified-Since",
+                                                    ts);
+             free(ts);
+          }
+     }
+
+   EINA_LIST_FOREACH(url_con->request_headers, n, header)
+     efl_net_dialer_http_request_header_add(url_con->dialer, header->key, 
header->value);
+
+   _c->curl_easy_setopt(curl_easy, CURLOPT_COOKIESESSION, 
(long)url_con->cookies.ignore_old_session);
+
+   EINA_LIST_FOREACH(url_con->cookies.files, n, s)
+     _c->curl_easy_setopt(curl_easy, CURLOPT_COOKIEFILE, s);
+
+   if (url_con->cookies.jar)
+     _c->curl_easy_setopt(curl_easy, CURLOPT_COOKIEJAR, url_con->cookies.jar);
+
+   EINA_LIST_FREE(url_con->cookies.cmds, s) /* free: only to execute once! */
+     _c->curl_easy_setopt(curl_easy, CURLOPT_COOKIELIST, s);
+
+   // Users should hook to their window animator if they want to show in 
real-time,
+   // or have a slower timer... but the old API requested a period event, so 
add it
+   // based on global animator timeout
+   url_con->progress.animator = 
ecore_animator_add(_ecore_con_url_progress_animator_cb, url_con);
+
+   DBG("prepared %p %s (%s), proxy=%s, primary_mode=%d",
+       url_con->dialer,
+       method,
+       efl_net_dialer_http_method_get(url_con->dialer),
+       efl_net_dialer_proxy_get(url_con->dialer),
+       efl_net_dialer_http_primary_mode_get(url_con->dialer));
+
+   free(proxy_url);
    return EINA_TRUE;
+
+ error_curl_easy:
+   _ecore_con_url_dialer_close(url_con);
+ error:
+   free(proxy_url);
+   return EINA_FALSE;
 }
 
-EAPI void
-ecore_con_url_cookies_jar_write(Ecore_Con_Url *url_obj)
+EAPI Ecore_Con_Url *
+ecore_con_url_new(const char *url)
 {
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return;
-   if (!_c) return;
+   Ecore_Con_Url *url_con;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(url, NULL);
+
+   url_con = calloc(1, sizeof(Ecore_Con_Url));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(url_con, NULL);
+
+   url_con->url = eina_stringshare_add(url);
+   url_con->http_version = EFL_NET_HTTP_VERSION_V1_1;
+   url_con->write_fd = -1;
+
+   EINA_MAGIC_SET(url_con, ECORE_MAGIC_CON_URL);
+   _url_con_url_list = eina_list_append(_url_con_url_list, url_con);
 
-   if (url_con->dead) return;
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIELIST, "FLUSH");
+   return url_con;
 }
 
-EAPI void
-ecore_con_url_verbose_set(Ecore_Con_Url *url_obj, Eina_Bool verbose)
+EAPI Ecore_Con_Url *
+ecore_con_url_custom_new(const char *url,
+                         const char *custom_request)
 {
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return;
-   if (!_c) return;
-   if (!url_con->url) return;
-   if (url_con->dead) return;
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_VERBOSE, (int)verbose);
+   Ecore_Con_Url *url_con;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(url, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(custom_request, NULL);
+
+   url_con = ecore_con_url_new(url);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(url_con, NULL);
+
+   url_con->custom_request = eina_stringshare_add(custom_request);
+
+   return url_con;
 }
 
 EAPI void
-ecore_con_url_ftp_use_epsv_set(Ecore_Con_Url *url_obj, Eina_Bool use_epsv)
+ecore_con_url_free(Ecore_Con_Url *url_con)
 {
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return;
-   if (!_c) return;
-   if (!url_con->url) return;
-   if (url_con->dead) return;
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_FTP_USE_EPSV,
-                        (int)use_epsv);
+   ECORE_CON_URL_CHECK_RETURN(url_con);
+   /* remove from list as early as possible, we don't want to call
+    * ecore_con_url_free() again on pending handles in ecore_con_url_shutdown()
+    */
+   _url_con_url_list = eina_list_remove(_url_con_url_list, url_con);
+   _ecore_con_url_free_internal(url_con);
+}
+
+EAPI void *
+ecore_con_url_data_get(Ecore_Con_Url *url_con)
+{
+   ECORE_CON_URL_CHECK_RETURN(url_con, NULL);
+   return url_con->data;
 }
 
-/**
- * Toggle libcurl's verify peer's certificate option.
- *
- * If @p verify is @c EINA_TRUE, libcurl will verify
- * the authenticity of the peer's certificate, otherwise
- * it will not. Default behavior of libcurl is to check
- * peer's certificate.
- *
- * @param url_con Ecore_Con_Url instance which will be acted upon.
- * @param verify Whether or not libcurl will check peer's certificate.
- * @since 1.1.0
- */
 EAPI void
-ecore_con_url_ssl_verify_peer_set(Ecore_Con_Url *url_obj, Eina_Bool verify)
+ecore_con_url_data_set(Ecore_Con_Url *url_con,
+                       void *data)
 {
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return;
-   if (!_c) return;
-   if (!url_con->url) return;
-   if (url_con->dead) return;
-   _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_SSL_VERIFYPEER,
-                        (int)verify);
+   ECORE_CON_URL_CHECK_RETURN(url_con);
+   url_con->data = data;
 }
 
-/**
- * Set a custom CA to trust for SSL/TLS connections.
- *
- * Specify the path of a file (in PEM format) containing one or more
- * CA certificate(s) to use for the validation of the server certificate.
- *
- * This function can also disable CA validation if @p ca_path is @c NULL.
- * However, the server certificate still needs to be valid for the connection
- * to succeed (i.e., the certificate must concern the server the
- * connection is made to).
- *
- * @param url_con Connection object that will use the custom CA.
- * @param ca_path Path to a CA certificate(s) file or @c NULL to disable
- *                CA validation.
- *
- * @return  @c 0 on success. When cURL is used, non-zero return values
- *          are equal to cURL error codes.
- */
-EAPI int
-ecore_con_url_ssl_ca_set(Ecore_Con_Url *url_obj, const char *ca_path)
+EAPI Eina_Bool
+ecore_con_url_url_set(Ecore_Con_Url *url_con,
+                      const char *url)
 {
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return -1;
-   int res = -1;
-
-   if (!_c) return -1;
-   if (!url_con->url) return -1;
-   if (url_con->dead) return -1;
-   if (ca_path == NULL)
-     res = _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_SSL_VERIFYPEER, 0);
-   else
-     {
-        res = _c->curl_easy_setopt(url_con->curl_easy,
-                                   CURLOPT_SSL_VERIFYPEER, 1);
-        if (!res)
-          res = _c->curl_easy_setopt(url_con->curl_easy,
-                                     CURLOPT_CAINFO, ca_path);
-     }
-   return res;
+   ECORE_CON_URL_CHECK_RETURN(url_con, EINA_FALSE);
+   eina_stringshare_replace(&url_con->url, url ? url : "");
+   return EINA_TRUE;
+}
+
+EAPI const char *
+ecore_con_url_url_get(Ecore_Con_Url *url_con)
+{
+   ECORE_CON_URL_CHECK_RETURN(url_con, NULL);
+   return url_con->url;
 }
 
+/* LEGACY: HTTP requests */
 EAPI Eina_Bool
-ecore_con_url_http_version_set(Ecore_Con_Url *url_obj, 
Ecore_Con_Url_Http_Version version)
+ecore_con_url_get(Ecore_Con_Url *url_con)
 {
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return EINA_FALSE;
-   int res = -1;
+   Eina_Error err;
 
-   if (!_c) return EINA_FALSE;
-   if (url_con->dead) return EINA_FALSE;
-   switch (version)
-     {
-      case ECORE_CON_URL_HTTP_VERSION_1_0:
-        res = _c->curl_easy_setopt(url_con->curl_easy,
-                                   CURLOPT_HTTP_VERSION,
-                                   CURL_HTTP_VERSION_1_0);
-        break;
+   ECORE_CON_URL_CHECK_RETURN(url_con, EINA_FALSE);
 
-      case ECORE_CON_URL_HTTP_VERSION_1_1:
-        res = _c->curl_easy_setopt(url_con->curl_easy,
-                                   CURLOPT_HTTP_VERSION,
-                                   CURL_HTTP_VERSION_1_1);
-        break;
+   if (!_ecore_con_url_request_prepare(url_con, "GET"))
+     return EINA_FALSE;
 
-      default:
-        break;
-     }
-   if (res != CURLE_OK)
+   err = efl_net_dialer_dial(url_con->dialer, url_con->url);
+   if (err)
      {
-        ERR("curl http version setting failed: %s", 
_c->curl_easy_strerror(res));
+        WRN("failed to HTTP GET '%s': %s", url_con->url, 
eina_error_msg_get(err));
+        _ecore_con_url_dialer_close(url_con);
         return EINA_FALSE;
      }
+
    return EINA_TRUE;
 }
 
 EAPI Eina_Bool
-ecore_con_url_proxy_set(Ecore_Con_Url *url_obj, const char *proxy)
+ecore_con_url_head(Ecore_Con_Url *url_con)
 {
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return EINA_FALSE;
-   int res = -1;
-   curl_version_info_data *vers = NULL;
-
-   if (!_c) return EINA_FALSE;
-   if (!url_con->url) return EINA_FALSE;
-   if (url_con->dead) return EINA_FALSE;
-   if (!proxy)
-     res = _c->curl_easy_setopt(url_con->curl_easy,
-                                CURLOPT_PROXY, "");
-   else
-     {
-        // before curl version 7.21.7, socks protocol:// prefix is not 
supported
-        // (e.g. socks4://, socks4a://, socks5:// or socks5h://, etc.)
-        vers = _c->curl_version_info(CURLVERSION_NOW);
-        if (vers->version_num < 0x71507)
-          {
-             url_con->proxy_type = CURLPROXY_HTTP;
-             if (strstr(proxy, "socks4a"))
-               url_con->proxy_type = CURLPROXY_SOCKS4A;
-             else if (strstr(proxy, "socks4"))
-               url_con->proxy_type = CURLPROXY_SOCKS4;
-             else if (strstr(proxy, "socks5h"))
-               url_con->proxy_type = CURLPROXY_SOCKS5_HOSTNAME;
-             else if (strstr(proxy, "socks5"))
-               url_con->proxy_type = CURLPROXY_SOCKS5;
-             res = _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_PROXYTYPE,
-                                        url_con->proxy_type);
-             if (res != CURLE_OK)
-               {
-                  ERR("curl proxy type setting failed: %s",
-                      _c->curl_easy_strerror(res));
-                  url_con->proxy_type = -1;
-                  return EINA_FALSE;
-               }
-          }
-        res = _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_PROXY, proxy);
-     }
-   if (res != CURLE_OK)
+   Eina_Error err;
+
+   ECORE_CON_URL_CHECK_RETURN(url_con, EINA_FALSE);
+
+   if (!_ecore_con_url_request_prepare(url_con, "HEAD"))
+     return EINA_FALSE;
+
+   err = efl_net_dialer_dial(url_con->dialer, url_con->url);
+   if (err)
      {
-        ERR("curl proxy setting failed: %s", _c->curl_easy_strerror(res));
-        url_con->proxy_type = -1;
+        WRN("failed to HTTP HEAD '%s': %s", url_con->url, 
eina_error_msg_get(err));
+        _ecore_con_url_dialer_close(url_con);
         return EINA_FALSE;
      }
-   return EINA_TRUE;
-}
 
-EAPI void
-ecore_con_url_timeout_set(Ecore_Con_Url *url_obj, double timeout)
-{
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return;
-   if (url_con->dead) return;
-   if (!url_con->url || timeout < 0) return;
-   if (url_con->timer) ecore_timer_del(url_con->timer);
-   url_con->timer = ecore_timer_add(timeout, _ecore_con_url_timeout_cb,
-                                    url_obj);
+   return EINA_TRUE;
 }
 
 EAPI Eina_Bool
-ecore_con_url_proxy_username_set(Ecore_Con_Url *url_obj, const char *username)
+ecore_con_url_post(Ecore_Con_Url *url_con,
+                   const void *data,
+                   long length,
+                   const char *content_type)
 {
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return EINA_FALSE;
-   int res = -1;
-
-   if (!_c) return EINA_FALSE;
-   if (url_con->dead) return EINA_FALSE;
-   if (!url_con->url) return EINA_FALSE;
-   if ((!username) || (!username[0])) return EINA_FALSE;
-   if ((url_con->proxy_type == CURLPROXY_SOCKS4) ||
-       (url_con->proxy_type == CURLPROXY_SOCKS4A))
+   Eo *buffer, *copier;
+   Eina_Slice slice = { .mem = data, .len = length };
+   Eina_Error err;
+
+   ECORE_CON_URL_CHECK_RETURN(url_con, EINA_FALSE);
+
+   if (!_ecore_con_url_request_prepare(url_con, "POST"))
+     return EINA_FALSE;
+
+   if (content_type)
+     efl_net_dialer_http_request_header_add(url_con->dialer, "Content-Type", 
content_type);
+
+   buffer = efl_add(EFL_IO_BUFFER_CLASS, efl_loop_get(url_con->dialer),
+                    efl_name_set(efl_added, "post-buffer"),
+                    efl_io_closer_close_on_destructor_set(efl_added, 
EINA_TRUE),
+                    efl_io_closer_close_on_exec_set(efl_added, EINA_TRUE));
+   EINA_SAFETY_ON_NULL_GOTO(buffer, error_buffer);
+
+   err = efl_io_writer_write(buffer, &slice, NULL);
+   if (err)
      {
-        ERR("Proxy type should be socks5 and above");
-        return EINA_FALSE;
+        WRN("could not populate buffer %p with %ld bytes: %s",
+            buffer, length, eina_error_msg_get(err));
+        goto error_copier;
      }
 
-   res = _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_USERNAME, username);
-   if (res != CURLE_OK)
+   copier = efl_add(EFL_IO_COPIER_CLASS, efl_loop_get(url_con->dialer),
+                    efl_name_set(efl_added, "send-copier"),
+                    efl_io_copier_source_set(efl_added, buffer),
+                    efl_io_copier_destination_set(efl_added, url_con->dialer),
+                    efl_io_closer_close_on_destructor_set(efl_added, 
EINA_FALSE),
+                    efl_event_callback_array_add(efl_added, 
_ecore_con_url_copier_cbs(), url_con));
+   EINA_SAFETY_ON_NULL_GOTO(copier, error_copier);
+
+   err = efl_net_dialer_dial(url_con->dialer, url_con->url);
+   if (err)
      {
-        ERR("curl_easy_setopt() failed: %s", _c->curl_easy_strerror(res));
-        return EINA_FALSE;
+        WRN("failed to post to '%s': %s", url_con->url, 
eina_error_msg_get(err));
+        goto error_dialer;
      }
+
+   url_con->input = buffer;
+   url_con->send_copier = copier;
+   DBG("posting to '%s' using an Efl.Io.Copier=%p", url_con->url, copier);
+
    return EINA_TRUE;
+
+ error_dialer:
+   efl_del(copier);
+ error_copier:
+   efl_del(buffer);
+ error_buffer:
+   _ecore_con_url_dialer_close(url_con);
+   return EINA_FALSE;
 }
 
-EAPI Eina_Bool
-ecore_con_url_proxy_password_set(Ecore_Con_Url *url_obj, const char *password)
+/* LEGACY: headers */
+EAPI void
+ecore_con_url_additional_header_add(Ecore_Con_Url *url_con,
+                                    const char *key,
+                                    const char *value)
 {
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return EINA_FALSE;
-   int res = -1;
-
-   if (!_c) return EINA_FALSE;
-   if (!url_con->url) return EINA_FALSE;
-   if (url_con->dead) return EINA_FALSE;
-   if (!password) return EINA_FALSE;
-   if (url_con->proxy_type == CURLPROXY_SOCKS4 || url_con->proxy_type == 
CURLPROXY_SOCKS4A)
-     {
-        ERR("Proxy type should be socks5 and above");
-        return EINA_FALSE;
-     }
-   res = _c->curl_easy_setopt(url_con->curl_easy, CURLOPT_PASSWORD, password);
-   if (res != CURLE_OK)
-     {
-        ERR("curl_easy_setopt() failed: %s", _c->curl_easy_strerror(res));
-        return EINA_FALSE;
-     }
-   return EINA_TRUE;
+   Efl_Net_Http_Header *header;
+   char *s;
+
+   ECORE_CON_URL_CHECK_RETURN(url_con);
+   EINA_SAFETY_ON_NULL_RETURN(key);
+   EINA_SAFETY_ON_NULL_RETURN(value);
+
+   header = malloc(sizeof(Efl_Net_Http_Header) +
+                   strlen(key) + 1 +
+                   strlen(value) + 1);
+   EINA_SAFETY_ON_NULL_RETURN(header);
+
+   header->key = s = (char *)header + sizeof(Efl_Net_Http_Header);
+   memcpy(s, key, strlen(key) + 1);
+
+   header->value = s = s + strlen(key) + 1;
+   memcpy(s, value, strlen(value) + 1);
+
+   url_con->request_headers = eina_list_append(url_con->request_headers,
+                                               header);
 }
 
-/**
- * @}
- */
+EAPI void
+ecore_con_url_additional_headers_clear(Ecore_Con_Url *url_con)
+{
+   ECORE_CON_URL_CHECK_RETURN(url_con);
+   _ecore_con_url_request_headers_free(url_con);
+}
 
-static void
-_ecore_con_url_status_get(Ecore_Con_Url *url_obj)
+EAPI void
+ecore_con_url_time(Ecore_Con_Url *url_con,
+                   Ecore_Con_Url_Time time_condition,
+                   double timestamp)
 {
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   long status = 0;
-
-   if (!_c) return;
-   if (!url_con->curl_easy) return;
-   if (!_c->curl_easy_getinfo(url_con->curl_easy, CURLINFO_RESPONSE_CODE,
-                              &status))
-     url_con->status = status;
-   else
-     url_con->status = 0;
+   ECORE_CON_URL_CHECK_RETURN(url_con);
+   url_con->time.condition = time_condition;
+   url_con->time.stamp = timestamp;
 }
 
-static void
-_ecore_con_url_event_url_complete(Ecore_Con_Url *url_obj, CURLMsg *curlmsg)
+/* LEGACY: cookies */
+EAPI void
+ecore_con_url_cookies_init(Ecore_Con_Url *url_con)
 {
-   Efl_Network_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   Efl_Network_Event_Url_Complete e;
-   int status = url_con->status;
+   CURL *curl_easy;
 
-   if (!_c) return;
+   ECORE_CON_URL_CHECK_RETURN(url_con);
 
-   if (!curlmsg)
-     ERR("Event completed without CURL message handle. Shouldn't happen");
-   else if ((curlmsg->msg == CURLMSG_DONE) &&
-            (curlmsg->data.result == CURLE_OPERATION_TIMEDOUT) &&
-            (!curlmsg->easy_handle))
-     {
-        /* easy_handle is set to NULL on timeout messages */
-        status = 408; /* Request Timeout */
-     }
-   else if (curlmsg->data.result == CURLE_OK)
-     {
-        if (!status)
-          {
-             _ecore_con_url_status_get(url_obj);
-             status = url_con->status;
-          }
-     }
-   else
-     {
-        ERR("Curl message have errors: %d (%s)",
-            curlmsg->data.result, 
_c->curl_easy_strerror(curlmsg->data.result));
-     }
-   e.status = status;
-   e.url_con = url_obj;
-   url_con->event_count++;
-   efl_event_callback_call(url_obj, EFL_NETWORK_URL_EVENT_COMPLETE, &e);
-}
+   /* meaningful before and after dial, persist and apply */
+   url_con->cookies.files = eina_list_append(url_con->cookies.files, 
eina_stringshare_add(""));
 
-static void
-_ecore_con_url_multi_remove(Ecore_Con_Url *url_obj)
-{
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   CURLMcode ret;
+   if (!url_con->dialer) return;
 
-   if (!_c) return;
-   ret = _c->curl_multi_remove_handle(_c->_curlm, url_con->curl_easy);
-   url_con->multi = EINA_FALSE;
-   if (ret != CURLM_OK) ERR("curl_multi_remove_handle failed: %s", 
_c->curl_multi_strerror(ret));
+   curl_easy = efl_net_dialer_http_curl_get(url_con->dialer);
+   EINA_SAFETY_ON_NULL_RETURN(curl_easy);
+
+   _c->curl_easy_setopt(curl_easy, CURLOPT_COOKIEFILE, "");
 }
 
-static Eina_Bool
-_ecore_con_url_timeout_cb(void *data)
+EAPI void
+ecore_con_url_cookies_file_add(Ecore_Con_Url *url_con,
+                               const char * const file_name)
 {
-   Ecore_Con_Url *url_obj = data;
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   CURLMsg timeout_msg;
+   CURL *curl_easy;
 
-   if (!_c) return ECORE_CALLBACK_CANCEL;
-   if (!url_obj) return ECORE_CALLBACK_CANCEL;
-   if (!url_con->curl_easy) return ECORE_CALLBACK_CANCEL;
+   ECORE_CON_URL_CHECK_RETURN(url_con);
+   EINA_SAFETY_ON_NULL_RETURN(file_name);
 
-   _ecore_con_url_multi_remove(url_obj);
-   _url_con_list = eina_list_remove(_url_con_list, url_obj);
+   /* meaningful before and after dial, persist and apply */
+   url_con->cookies.files = eina_list_append(url_con->cookies.files, 
eina_stringshare_add(file_name));
 
-   _c->curl_slist_free_all(url_con->headers);
-   url_con->headers = NULL;
+   if (!url_con->dialer) return;
 
-   url_con->timer = NULL;
-
-   timeout_msg.msg = CURLMSG_DONE;
-   timeout_msg.easy_handle = NULL;
-   timeout_msg.data.result = CURLE_OPERATION_TIMEDOUT;
+   curl_easy = efl_net_dialer_http_curl_get(url_con->dialer);
+   EINA_SAFETY_ON_NULL_RETURN(curl_easy);
 
-   _ecore_con_url_event_url_complete(url_obj, &timeout_msg);
-   return ECORE_CALLBACK_CANCEL;
+   _c->curl_easy_setopt(curl_easy, CURLOPT_COOKIEFILE, file_name);
 }
 
-static size_t
-_ecore_con_url_data_cb(void *buffer, size_t size, size_t nitems, void *userp)
+EAPI void
+ecore_con_url_cookies_clear(Ecore_Con_Url *url_con)
 {
-   Efl_Network_Url *url_obj = (Efl_Network_Url *)userp;
-   Efl_Network_Event_Url_Data e;
-   size_t real_size = size * nitems;
+   static const char cookielist_cmd_all[] = "ALL";
+   CURL *curl_easy;
 
-   Efl_Network_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return -1;
+   ECORE_CON_URL_CHECK_RETURN(url_con);
 
-   url_con->received += real_size;
-   INF("reading from %s", url_con->url);
-   if (url_con->write_fd < 0)
+   /* only meaningful once, if not dialed, queue, otherwise execute */
+   if (!url_con->dialer)
      {
-        e.url_con = url_obj;
-        e.size = real_size;
-        e.data = buffer;
-        url_con->event_count++;
-        efl_event_callback_call(url_obj, EFL_NETWORK_URL_EVENT_DATA, &e);
+        url_con->cookies.cmds = eina_list_append(url_con->cookies.cmds, 
cookielist_cmd_all);
+        return;
      }
-   else
-     {
-        ssize_t count = 0;
-        size_t total_size = real_size;
-        size_t offset = 0;
 
-        while (total_size > 0)
-          {
-             count = write(url_con->write_fd,
-                           (char *)buffer + offset,
-                           total_size);
-             if (count < 0)
-               {
-                  if ((errno != EAGAIN) && (errno != EINTR)) return -1;
-               }
-             else
-               {
-                  total_size -= count;
-                  offset += count;
-               }
-          }
+   curl_easy = efl_net_dialer_http_curl_get(url_con->dialer);
+   EINA_SAFETY_ON_NULL_RETURN(curl_easy);
+
+   _c->curl_easy_setopt(curl_easy, CURLOPT_COOKIELIST, cookielist_cmd_all);
+}
+
+EAPI void
+ecore_con_url_cookies_session_clear(Ecore_Con_Url *url_con)
+{
+   static const char cookielist_cmd_sess[] = "SESS";
+   CURL *curl_easy;
+
+   ECORE_CON_URL_CHECK_RETURN(url_con);
+
+   /* only meaningful once, if not dialed, queue, otherwise execute */
+   if (!url_con->dialer)
+     {
+        url_con->cookies.cmds = eina_list_append(url_con->cookies.cmds, 
cookielist_cmd_sess);
+        return;
      }
-   return real_size;
+
+   curl_easy = efl_net_dialer_http_curl_get(url_con->dialer);
+   EINA_SAFETY_ON_NULL_RETURN(curl_easy);
+
+   _c->curl_easy_setopt(curl_easy, CURLOPT_COOKIELIST, cookielist_cmd_sess);
 }
 
-static size_t
-_ecore_con_url_header_cb(void *ptr, size_t size, size_t nitems, void *stream)
+EAPI void
+ecore_con_url_cookies_ignore_old_session_set(Ecore_Con_Url *url_con,
+                                             Eina_Bool ignore)
 {
-   size_t real_size = size * nitems;
-   Ecore_Con_Url *url_obj = stream;
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   if (!efl_isa(url_obj, EFL_NETWORK_URL_CLASS))
-      return 0;
-
-   char *header = malloc(sizeof(char) * (real_size + 1));
-   if (!header) return real_size;
-   memcpy(header, ptr, real_size);
-   header[real_size] = '\0';
-   url_con->response_headers = eina_list_append(url_con->response_headers,
-                                                header);
-   return real_size;
+   ECORE_CON_URL_CHECK_RETURN(url_con);
+   url_con->cookies.ignore_old_session = ignore;
 }
 
-static int
-_ecore_con_url_progress_cb(void *clientp, double dltotal, double dlnow, double 
ultotal, double ulnow)
+EAPI Eina_Bool
+ecore_con_url_cookies_jar_file_set(Ecore_Con_Url *url_con,
+                                   const char * const cookiejar_file)
 {
-   Efl_Network_Event_Url_Progress e;
-   Efl_Network_Url *url_obj = clientp;
+   CURL *curl_easy;
 
-   Efl_Network_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
+   ECORE_CON_URL_CHECK_RETURN(url_con, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(cookiejar_file, EINA_FALSE);
 
-   e.url_con = url_obj;
-   e.down.total = dltotal;
-   e.down.now = dlnow;
-   e.up.total = ultotal;
-   e.up.now = ulnow;
-   url_con->event_count++;
-   efl_event_callback_call(url_obj, EFL_NETWORK_URL_EVENT_PROGRESS, &e);
+   /* meaningful before and after dial, persist and apply */
+   eina_stringshare_replace(&url_con->cookies.jar, cookiejar_file);
 
-   return 0;
+   if (!url_con->dialer) return EINA_TRUE;
+
+   curl_easy = efl_net_dialer_http_curl_get(url_con->dialer);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(curl_easy, EINA_FALSE);
+
+   _c->curl_easy_setopt(curl_easy, CURLOPT_COOKIEJAR, url_con->cookies.jar);
+   return EINA_TRUE;
 }
 
-static size_t
-_ecore_con_url_read_cb(void *ptr, size_t size, size_t nitems, void *stream)
+EAPI void
+ecore_con_url_cookies_jar_write(Ecore_Con_Url *url_con)
 {
-   size_t retcode = fread(ptr, size, nitems, stream);
+   CURL *curl_easy;
 
-   if (ferror((FILE *)stream))
-     {
-        fclose(stream);
-        return CURL_READFUNC_ABORT;
-     }
-   else if (retcode == 0)
-     {
-        fclose((FILE *)stream);
-        return 0;
-     }
-   INF("*** We read %zu bytes from file", retcode);
-   return retcode;
+   ECORE_CON_URL_CHECK_RETURN(url_con);
+
+   /* only meaningful after dialed */
+   if (!url_con->dialer) return;
+
+   curl_easy = efl_net_dialer_http_curl_get(url_con->dialer);
+   EINA_SAFETY_ON_NULL_RETURN(curl_easy);
+
+   _c->curl_easy_setopt(curl_easy, CURLOPT_COOKIELIST, "FLUSH");
 }
 
-static void
-_ecore_con_url_info_read(void)
+/* LEGACY: file upload/download */
+EAPI void
+ecore_con_url_fd_set(Ecore_Con_Url *url_con, int fd)
 {
-   CURLMsg *curlmsg;
-   int n_remaining;
+   ECORE_CON_URL_CHECK_RETURN(url_con);
 
-   if (!_c) return;
-   while ((curlmsg = _c->curl_multi_info_read(_c->_curlm, &n_remaining)))
-     {
-        Eina_List *l, *ll;
-        Ecore_Con_Url *url_obj = NULL;
+   if (url_con->write_fd == fd) return;
 
-        DBG("Curl message: %d", curlmsg->msg);
-        if (curlmsg->msg == CURLMSG_DONE)
-          {
-             EINA_LIST_FOREACH_SAFE(_url_con_list, l, ll, url_obj)
-               {
-                  Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, 
MY_CLASS);
-                  if (curlmsg->easy_handle == url_con->curl_easy)
-                    _ecore_con_url_event_url_complete(url_obj, curlmsg);
-               }
-          }
+   url_con->write_fd = fd;
+   if (!url_con->dialer) return;
+}
+
+EAPI Eina_Bool
+ecore_con_url_ftp_upload(Ecore_Con_Url *url_con,
+                         const char *filename,
+                         const char *user,
+                         const char *pass,
+                         const char *upload_dir)
+{
+   char tmp[4096];
+   char *bname;
+   Eo *file, *copier;
+   Eina_Error err;
+
+   ECORE_CON_URL_CHECK_RETURN(url_con, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(filename, EINA_FALSE);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(filename[0] == '\0', EINA_FALSE);
+
+   bname = strdup(filename);
+   if (upload_dir)
+     snprintf(tmp, sizeof(tmp), "%s/%s/%s", url_con->url, upload_dir, 
basename(bname));
+   else
+     snprintf(tmp, sizeof(tmp), "%s/%s", url_con->url, basename(bname));
+   free(bname);
+
+   if (!_ecore_con_url_request_prepare(url_con, "PUT"))
+     return EINA_FALSE;
+
+   efl_net_dialer_http_authentication_set(url_con->dialer, user, pass, 
EFL_NET_HTTP_AUTHENTICATION_METHOD_ANY, EINA_FALSE);
+
+   file = efl_add(EFL_IO_FILE_CLASS, efl_loop_get(url_con->dialer),
+                  efl_name_set(efl_added, "upload-file"),
+                  efl_file_set(efl_added, filename, NULL),
+                  efl_io_file_flags_set(efl_added, O_RDONLY),
+                  efl_io_closer_close_on_destructor_set(efl_added, EINA_TRUE),
+                  efl_io_closer_close_on_exec_set(efl_added, EINA_TRUE));
+   EINA_SAFETY_ON_NULL_GOTO(file, error_file);
+
+   copier = efl_add(EFL_IO_COPIER_CLASS, efl_loop_get(url_con->dialer),
+                    efl_name_set(efl_added, "send-copier"),
+                    efl_io_copier_source_set(efl_added, file),
+                    efl_io_copier_destination_set(efl_added, url_con->dialer),
+                    efl_io_closer_close_on_destructor_set(efl_added, 
EINA_FALSE),
+                    efl_event_callback_array_add(efl_added, 
_ecore_con_url_copier_cbs(), url_con));
+   EINA_SAFETY_ON_NULL_GOTO(copier, error_copier);
+
+   err = efl_net_dialer_dial(url_con->dialer, tmp);
+   if (err)
+     {
+        WRN("failed to upload file '%s' to '%s': %s", filename, tmp, 
eina_error_msg_get(err));
+        goto error_dialer;
      }
+
+   url_con->input = file;
+   url_con->send_copier = copier;
+   DBG("uploading file '%s' to '%s' using an Efl.Io.Copier=%p", filename, tmp, 
copier);
+
+   return EINA_TRUE;
+
+ error_dialer:
+   efl_del(copier);
+ error_copier:
+   efl_del(file);
+ error_file:
+   _ecore_con_url_dialer_close(url_con);
+   return EINA_FALSE;
 }
 
-static void
-_ecore_con_url_curl_clear(void)
+EAPI void
+ecore_con_url_ftp_use_epsv_set(Ecore_Con_Url *url_con,
+                               Eina_Bool use_epsv)
 {
-   Ecore_Fd_Handler *fdh;
-   Ecore_Con_Url *url_con;
+   ECORE_CON_URL_CHECK_RETURN(url_con);
+   url_con->ftp_use_epsv = use_epsv;
+}
 
-   EINA_LIST_FREE(_fd_hd_list, fdh)
-     ecore_main_fd_handler_del(fdh);
-   EINA_LIST_FREE(_url_con_list, url_con)
-     _ecore_con_url_multi_remove(url_con);
+/* LEGACY: proxy */
+EAPI Eina_Bool
+ecore_con_url_proxy_password_set(Ecore_Con_Url *url_con, const char *password)
+{
+   ECORE_CON_URL_CHECK_RETURN(url_con, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(password, EINA_FALSE);
+   eina_stringshare_replace(&url_con->proxy.password, password);
+   return EINA_TRUE;
 }
 
-static Eina_Bool
-_ecore_con_url_do_multi_timeout(long *retms)
+EAPI Eina_Bool
+ecore_con_url_proxy_username_set(Ecore_Con_Url *url_con, const char *username)
 {
-   long ms = 0;
-   int ret;
+   ECORE_CON_URL_CHECK_RETURN(url_con, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(username, EINA_FALSE);
+   eina_stringshare_replace(&url_con->proxy.username, username);
+   return EINA_TRUE;
+}
 
-   ret = _c->curl_multi_timeout(_c->_curlm, &ms);
-   *retms = ms;
-   if (!ret)
-     {
-        if (!ms)
-          {
-             _ecore_con_url_timer(NULL);
-             DBG("multiperform is still running: timeout: %ld", ms);
-          }
-        return EINA_TRUE;
-     }
-   else
-     {
-         ERR("curl_multi_perform() failed: %s",
-              _c->curl_multi_strerror(ret));
-         _ecore_con_url_curl_clear();
-         ecore_timer_freeze(_curl_timer);
+EAPI Eina_Bool
+ecore_con_url_proxy_set(Ecore_Con_Url *url_con, const char *proxy_url)
+{
+   ECORE_CON_URL_CHECK_RETURN(url_con, EINA_FALSE);
+   eina_stringshare_replace(&url_con->proxy.url, proxy_url);
+   return EINA_TRUE;
+}
 
-         return EINA_FALSE;
-     }
+/* LEGACY: response */
+EAPI int
+ecore_con_url_received_bytes_get(Ecore_Con_Url *url_con)
+{
+   ECORE_CON_URL_CHECK_RETURN(url_con, EINA_FALSE);
+   return url_con->received_bytes;
 }
 
-static Eina_Bool
-_ecore_con_url_fd_handler(void *data EINA_UNUSED, Ecore_Fd_Handler *fd_handler 
EINA_UNUSED)
+EAPI int
+ecore_con_url_status_code_get(Ecore_Con_Url *url_con)
 {
-   Ecore_Fd_Handler *fdh;
-   long ms = 0;
-
-   if (!_c) return ECORE_CALLBACK_CANCEL;
-   EINA_LIST_FREE(_fd_hd_list, fdh)
-     ecore_main_fd_handler_del(fdh);
-   if (!_ecore_con_url_do_multi_timeout(&ms)) return EINA_FALSE;
-   if ((ms >= CURL_MIN_TIMEOUT) || (ms <= 0)) ms = CURL_MIN_TIMEOUT;
-   ecore_timer_interval_set(_curl_timer, (double)ms / 1000.0);
-   ecore_timer_reset(_curl_timer);
-   _ecore_con_url_timer(NULL);
-   return ECORE_CALLBACK_CANCEL;
+   ECORE_CON_URL_CHECK_RETURN(url_con, 0);
+   if (!url_con->dialer) return url_con->status;
+   return efl_net_dialer_http_response_status_get(url_con->dialer);
 }
 
-static void
-_ecore_con_url_fdset(void)
+EAPI const Eina_List *
+ecore_con_url_response_headers_get(Ecore_Con_Url *url_con)
 {
-   CURLMcode ret;
-   fd_set read_set, write_set, exc_set;
-   int fd, fd_max;
+   ECORE_CON_URL_CHECK_RETURN(url_con, NULL);
+   return url_con->response_headers;
+}
 
-   if (!_c) return;
+/* LEGACY: SSL */
+EAPI int
+ecore_con_url_ssl_ca_set(Ecore_Con_Url *url_con,
+                         const char *ca_path)
+{
+   ECORE_CON_URL_CHECK_RETURN(url_con, -1);
+   eina_stringshare_replace(&url_con->ca_path, ca_path);
+   url_con->ssl_verify_peer = !!ca_path;
+   return 0;
+}
 
-   FD_ZERO(&read_set);
-   FD_ZERO(&write_set);
-   FD_ZERO(&exc_set);
+EAPI void
+ecore_con_url_ssl_verify_peer_set(Ecore_Con_Url *url_con,
+                                  Eina_Bool verify)
+{
+   ECORE_CON_URL_CHECK_RETURN(url_con);
+   url_con->ssl_verify_peer = !!verify;
+}
 
-   ret = _c->curl_multi_fdset(_c->_curlm, &read_set,
-                              &write_set, &exc_set, &fd_max);
-   if (ret != CURLM_OK)
-     {
-        ERR("curl_multi_fdset failed: %s", _c->curl_multi_strerror(ret));
-        return;
-     }
+/* LEGACY: misc */
+EAPI Eina_Bool
+ecore_con_url_httpauth_set(Ecore_Con_Url *url_con,
+                           const char *username,
+                           const char *password,
+                           Eina_Bool safe)
+{
+   ECORE_CON_URL_CHECK_RETURN(url_con, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(username, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(password, EINA_FALSE);
+
+   eina_stringshare_replace(&url_con->httpauth.username, username);
+   eina_stringshare_replace(&url_con->httpauth.password, password);
+   url_con->httpauth.method = safe ? 
EFL_NET_HTTP_AUTHENTICATION_METHOD_ANY_SAFE : 
EFL_NET_HTTP_AUTHENTICATION_METHOD_ANY;
+   url_con->httpauth.restricted = safe;
+   return EINA_TRUE;
+}
 
-   for (fd = 0; fd <= fd_max; fd++)
+EAPI Eina_Bool
+ecore_con_url_http_version_set(Ecore_Con_Url *url_con, 
Ecore_Con_Url_Http_Version version)
+{
+   ECORE_CON_URL_CHECK_RETURN(url_con, EINA_FALSE);
+   switch (version)
      {
-        int flags = 0;
-        if (FD_ISSET(fd, &read_set)) flags |= ECORE_FD_READ;
-        if (FD_ISSET(fd, &write_set)) flags |= ECORE_FD_WRITE;
-        if (FD_ISSET(fd, &exc_set)) flags |= ECORE_FD_ERROR;
-        if (flags)
-          {
-             // FIXME: Who is owner (easy_handle) of this fd??
-             // (Curl do not give this info.)
-             // This cause "Failed to delete epoll fd xx!" error messages
-             Ecore_Fd_Handler *fd_handler;
-             fd_handler = ecore_main_fd_handler_add(fd, flags,
-                                                    _ecore_con_url_fd_handler,
-                                                    NULL, NULL, NULL);
-             if (fd_handler)
-               _fd_hd_list = eina_list_append(_fd_hd_list, fd_handler);
-          }
+      case ECORE_CON_URL_HTTP_VERSION_1_0:
+         url_con->http_version = EFL_NET_HTTP_VERSION_V1_0;
+         break;
+      case ECORE_CON_URL_HTTP_VERSION_1_1:
+         url_con->http_version = EFL_NET_HTTP_VERSION_V1_1;
+         break;
+      default:
+         ERR("unknown HTTP version enum value %d", version);
+         return EINA_FALSE;
      }
+   return EINA_TRUE;
 }
 
 static Eina_Bool
-_ecore_con_url_timer(void *data EINA_UNUSED)
+_ecore_con_url_timeout_cb(void *data)
 {
-   Ecore_Fd_Handler *fdh;
-   int still_running;
-   CURLMcode ret;
-
-   EINA_LIST_FREE(_fd_hd_list, fdh)
-     ecore_main_fd_handler_del(fdh);
-   _ecore_con_url_info_read();
-   if (!_c) return ECORE_CALLBACK_RENEW;
-   ret = _c->curl_multi_perform(_c->_curlm, &still_running);
-   if (ret == CURLM_CALL_MULTI_PERFORM)
-     {
-        DBG("curl_multi_perform() again immediately");
-        ecore_timer_interval_set(_curl_timer, 0.000001);
-        return ECORE_CALLBACK_RENEW;
-     }
-   else if (ret != CURLM_OK)
-     {
-        ERR("curl_multi_perform() failed: %s", _c->curl_multi_strerror(ret));
-        _ecore_con_url_curl_clear();
-        ecore_timer_freeze(_curl_timer);
-     }
-   if (still_running)
-     {
-        long ms = 0;
-
-        _ecore_con_url_fdset();
-        if (!_ecore_con_url_do_multi_timeout(&ms)) return EINA_FALSE;
-        DBG("multiperform is still running: %d, timeout: %ld",
-            still_running, ms);
-        if ((ms >= CURL_MIN_TIMEOUT) || (ms < 0)) ms = CURL_MIN_TIMEOUT;
-        ecore_timer_interval_set(_curl_timer, (double)ms / 1000.0);
-     }
-   else
+   Ecore_Con_Url *url_con = data;
+   int status;
+
+   url_con->timer = NULL;
+
+   WRN("HTTP timeout url='%s'", 
efl_net_dialer_address_dial_get(url_con->dialer));
+
+   status = efl_net_dialer_http_response_status_get(url_con->dialer);
+   if ((status < 500) && (status > 599))
      {
-        DBG("multiperform ended");
-        _ecore_con_url_info_read();
-        _ecore_con_url_curl_clear();
-        ecore_timer_freeze(_curl_timer);
+        DBG("HTTP error %d reset to 1", status);
+        status = 1; /* not a real HTTP error */
      }
-   return ECORE_CALLBACK_RENEW;
+
+   _ecore_con_event_url_complete_add(url_con, status);
+
+   return EINA_FALSE;
 }
 
-static Eina_Bool
-_ecore_con_url_perform(Ecore_Con_Url *url_obj)
+EAPI void
+ecore_con_url_timeout_set(Ecore_Con_Url *url_con, double timeout)
 {
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
-   CURLMcode ret;
+   ECORE_CON_URL_CHECK_RETURN(url_con);
 
-   if (!_c) return EINA_FALSE;
-   ret = _c->curl_multi_add_handle(_c->_curlm, url_con->curl_easy);
-   if (ret != CURLM_OK)
+   if (url_con->timer)
      {
-        ERR("curl_multi_add_handle() failed: %s",
-            _c->curl_multi_strerror(ret));
-        return EINA_FALSE;
+        ecore_timer_del(url_con->timer);
+        url_con->timer = NULL;
      }
-   url_con->multi = EINA_TRUE;
-   _url_con_list = eina_list_append(_url_con_list, url_obj);
-   ecore_timer_thaw(_curl_timer);
-   return EINA_TRUE;
+
+   if (timeout <= 0.0) return;
+
+   // NOTE: it is weird to start the timeout right away here, but it
+   // was done like that and we're keeping it for compatibility
+   url_con->timer = ecore_timer_add(timeout, _ecore_con_url_timeout_cb, 
url_con);
 }
 
-static void
-_ecore_con_event_url_free(Ecore_Con_Url *url_obj, void *ev)
+EAPI void
+ecore_con_url_verbose_set(Ecore_Con_Url *url_con,
+                          Eina_Bool verbose)
 {
-   Ecore_Con_Url_Data *url_con = efl_data_scope_get(url_obj, MY_CLASS);
+   CURL *curl_easy;
 
-   free(ev);
-   url_con->event_count--;
-   if (url_con->dead && (!url_con->event_count))
+   ECORE_CON_URL_CHECK_RETURN(url_con);
+
+   /* meaningful before and after dial, persist and apply */
+   url_con->verbose = !!verbose;
+
+   if (!url_con->dialer) return;
+
+   curl_easy = efl_net_dialer_http_curl_get(url_con->dialer);
+   EINA_SAFETY_ON_NULL_RETURN(curl_easy);
+
+   if (url_con->verbose)
      {
-        _ecore_con_url_free_internal(url_obj);
-        efl_manual_free(url_obj);
+        _c->curl_easy_setopt(curl_easy, CURLOPT_DEBUGFUNCTION, NULL);
+        _c->curl_easy_setopt(curl_easy, CURLOPT_DEBUGDATA, NULL);
+        DBG("HTTP Dialer %p is set to legacy debug function (CURL's default, 
no eina_log)", url_con->dialer);
      }
+   _c->curl_easy_setopt(curl_easy, CURLOPT_VERBOSE, (long)url_con->verbose);
 }
-
-#include "efl_network_url.eo.c"
-#include "ecore_con_legacy.c"
diff --git a/src/lib/ecore_con/efl_network_url.eo 
b/src/lib/ecore_con/efl_network_url.eo
deleted file mode 100644
index 9dacb51..0000000
--- a/src/lib/ecore_con/efl_network_url.eo
+++ /dev/null
@@ -1,29 +0,0 @@
-class Efl.Network.Url (Efl.Object) {
-   [[Uniform Resource Locator (URL) base class]]
-   eo_prefix: efl_network_url;
-   methods {
-      @property url {
-         [[Controls the URL to send the request to.]]
-         set {
-            return: bool (false); [[$true on success, $false on error.]]
-         }
-         get {
-         }
-         values {
-            url: string; [[The URL]]
-         }
-      }
-   }
-   implements {
-        Efl.Object.constructor;
-        Efl.Object.destructor;
-        Efl.Object.finalize;
-   }
-   events {
-      data; [[Triggered when data arrives at the socket.]]
-      progress; [[Triggered when progress is made in upload/download.]]
-      complete; [[Triggered when the operation is complete.]]
-   }
-}
-
-/* FIXME: Actually migrate all of the functions. */

-- 


Reply via email to