[evolution/wip/webkit2] Use former SoupRequest descendants again



commit 07d1d97e49a9bc486b22f26a3f7d47e8b1c16c71
Author: Milan Crha <mcrha redhat com>
Date:   Thu Mar 24 18:50:00 2016 +0100

    Use former SoupRequest descendants again
    
    This also fixed contact photo preview in the Contacts view.

 e-util/Makefile.am         |    2 +
 e-util/e-content-request.c |  188 ++++++++++
 e-util/e-content-request.h |   93 +++++
 e-util/e-file-request.c    |  222 +++++--------
 e-util/e-file-request.h    |   11 +-
 e-util/e-misc-utils.c      |   16 +
 e-util/e-misc-utils.h      |    3 +
 e-util/e-stock-request.c   |  266 +++++++--------
 e-util/e-stock-request.h   |   11 +-
 e-util/e-util.h            |    1 +
 e-util/e-web-view.c        |  292 +++++-----------
 e-util/e-web-view.h        |    5 +
 mail/Makefile.am           |    2 +
 mail/e-cid-request.c       |  140 ++++++++
 mail/e-cid-request.h       |   62 ++++
 mail/e-http-request.c      |  319 ++++++------------
 mail/e-http-request.h      |   12 +-
 mail/e-mail-display.c      |  829 +------------------------------------------
 mail/e-mail-request.c      |  455 +++++++++++--------------
 mail/e-mail-request.h      |   11 +-
 shell/main.c               |    1 +
 21 files changed, 1143 insertions(+), 1798 deletions(-)
---
diff --git a/e-util/Makefile.am b/e-util/Makefile.am
index cd49da4..161ef22 100644
--- a/e-util/Makefile.am
+++ b/e-util/Makefile.am
@@ -174,6 +174,7 @@ evolution_util_include_HEADERS =  \
        e-config.h \
        e-conflict-search-selector.h \
        e-contact-store.h \
+       e-content-request.h \
        e-data-capture.h \
        e-dateedit.h \
        e-datetime-format.h \
@@ -449,6 +450,7 @@ libevolution_util_la_SOURCES = \
        e-config.c \
        e-conflict-search-selector.c \
        e-contact-store.c \
+       e-content-request.c \
        e-data-capture.c \
        e-dateedit.c \
        e-datetime-format.c \
diff --git a/e-util/e-content-request.c b/e-util/e-content-request.c
new file mode 100644
index 0000000..9448d44
--- /dev/null
+++ b/e-util/e-content-request.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "e-content-request.h"
+
+G_DEFINE_INTERFACE (EContentRequest, e_content_request, G_TYPE_OBJECT)
+
+static void
+e_content_request_default_init (EContentRequestInterface *iface)
+{
+}
+
+gboolean
+e_content_request_can_process_uri (EContentRequest *request,
+                                  const gchar *uri)
+{
+       EContentRequestInterface *iface;
+
+       g_return_val_if_fail (E_IS_CONTENT_REQUEST (request), FALSE);
+       g_return_val_if_fail (uri != NULL, FALSE);
+
+       iface = E_CONTENT_REQUEST_GET_INTERFACE (request);
+       g_return_val_if_fail (iface != NULL, FALSE);
+       g_return_val_if_fail (iface->can_process_uri != NULL, FALSE);
+
+       return iface->can_process_uri (request, uri);
+}
+
+gboolean
+e_content_request_process_sync (EContentRequest *request,
+                               const gchar *uri,
+                               GObject *requester,
+                               GInputStream **out_stream,
+                               gint64 *out_stream_length,
+                               gchar **out_mime_type,
+                               GCancellable *cancellable,
+                               GError **error)
+{
+       EContentRequestInterface *iface;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (E_IS_CONTENT_REQUEST (request), FALSE);
+       g_return_val_if_fail (uri != NULL, FALSE);
+       g_return_val_if_fail (G_IS_OBJECT (requester), FALSE);
+       g_return_val_if_fail (out_stream != NULL, FALSE);
+       g_return_val_if_fail (out_stream_length != NULL, FALSE);
+       g_return_val_if_fail (out_mime_type != NULL, FALSE);
+
+       iface = E_CONTENT_REQUEST_GET_INTERFACE (request);
+       g_return_val_if_fail (iface != NULL, FALSE);
+       g_return_val_if_fail (iface->process_sync != NULL, FALSE);
+
+       if (!iface->process_sync (request, uri, requester, out_stream, out_stream_length, out_mime_type, 
cancellable, &local_error)) {
+               if (!local_error)
+                       local_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, g_strerror 
(ENOENT));
+
+               g_propagate_error (error, local_error);
+
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+typedef struct _ThreadData
+{
+       gchar *uri;
+       GObject *requester;
+       GInputStream *out_stream;
+       gint64 out_stream_length;
+       gchar *out_mime_type;
+} ThreadData;
+
+static void
+thread_data_free (gpointer ptr)
+{
+       ThreadData *td = ptr;
+
+       if (td) {
+               g_clear_object (&td->out_stream);
+               g_clear_object (&td->requester);
+               g_free (td->uri);
+               g_free (td->out_mime_type);
+               g_free (td);
+       }
+}
+
+static void
+content_request_process_thread (GTask *task,
+                               gpointer source_object,
+                               gpointer task_data,
+                               GCancellable *cancellable)
+{
+       ThreadData *td = task_data;
+       GError *local_error = NULL;
+
+       g_return_if_fail (E_IS_CONTENT_REQUEST (source_object));
+       g_return_if_fail (td != NULL);
+
+       if (!e_content_request_process_sync (E_CONTENT_REQUEST (source_object),
+               td->uri, td->requester, &td->out_stream, &td->out_stream_length, &td->out_mime_type,
+               cancellable, &local_error)) {
+               g_task_return_error (task, local_error);
+       } else {
+               g_task_return_boolean (task, TRUE);
+       }
+}
+
+void
+e_content_request_process (EContentRequest *request,
+                          const gchar *uri,
+                          GObject *requester,
+                          GCancellable *cancellable,
+                          GAsyncReadyCallback callback,
+                          gpointer user_data)
+{
+       GTask *task;
+       ThreadData *td;
+
+       g_return_if_fail (E_IS_CONTENT_REQUEST (request));
+       g_return_if_fail (uri != NULL);
+       g_return_if_fail (G_IS_OBJECT (requester));
+
+       td = g_new0 (ThreadData, 1);
+       td->uri = g_strdup (uri);
+       td->requester = g_object_ref (requester);
+
+       task = g_task_new (request, cancellable, callback, user_data);
+       g_task_set_task_data (task, td, thread_data_free);
+       g_task_run_in_thread (task, content_request_process_thread);
+       g_object_unref (task);
+}
+
+gboolean
+e_content_request_process_finish (EContentRequest *request,
+                                 GAsyncResult *result,
+                                 GInputStream **out_stream,
+                                 gint64 *out_stream_length,
+                                 gchar **out_mime_type,
+                                 GError **error)
+{
+       ThreadData *td;
+
+       g_return_val_if_fail (g_task_is_valid (result, request), FALSE);
+       g_return_val_if_fail (E_IS_CONTENT_REQUEST (request), FALSE);
+       g_return_val_if_fail (G_IS_TASK (result), FALSE);
+       g_return_val_if_fail (out_stream != NULL, FALSE);
+       g_return_val_if_fail (out_stream_length != NULL, FALSE);
+       g_return_val_if_fail (out_mime_type != NULL, FALSE);
+
+       td = g_task_get_task_data (G_TASK (result));
+       g_return_val_if_fail (td != NULL, FALSE);
+
+       if (!g_task_propagate_boolean (G_TASK (result), error))
+               return FALSE;
+
+       *out_stream = td->out_stream;
+       *out_stream_length = td->out_stream_length;
+       *out_mime_type = td->out_mime_type;
+
+       td->out_stream = NULL;
+       td->out_mime_type = NULL;
+
+       return TRUE;
+}
diff --git a/e-util/e-content-request.h b/e-util/e-content-request.h
new file mode 100644
index 0000000..7df94c4
--- /dev/null
+++ b/e-util/e-content-request.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION)
+#error "Only <e-util/e-util.h> should be included directly."
+#endif
+
+#ifndef E_CONTENT_REQUEST_H
+#define E_CONTENT_REQUEST_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CONTENT_REQUEST \
+       (e_content_request_get_type ())
+#define E_CONTENT_REQUEST(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_CONTENT_REQUEST, EContentRequest))
+#define E_CONTENT_REQUEST_INTERFACE(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_CONTENT_REQUEST, EContentRequestInterface))
+#define E_IS_CONTENT_REQUEST(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_CONTENT_REQUEST))
+#define E_IS_CONTENT_REQUEST_INTERFACE(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_CONTENT_REQUEST))
+#define E_CONTENT_REQUEST_GET_INTERFACE(obj) \
+       (G_TYPE_INSTANCE_GET_INTERFACE \
+       ((obj), E_TYPE_CONTENT_REQUEST, EContentRequestInterface))
+
+G_BEGIN_DECLS
+
+typedef struct _EContentRequest EContentRequest;
+typedef struct _EContentRequestInterface EContentRequestInterface;
+
+struct _EContentRequestInterface {
+       GTypeInterface parent_interface;
+
+       gboolean        (* can_process_uri)     (EContentRequest *request,
+                                                const gchar *uri);
+       gboolean        (* process_sync)        (EContentRequest *request,
+                                                const gchar *uri,
+                                                GObject *requester,
+                                                GInputStream **out_stream,
+                                                gint64 *out_stream_length,
+                                                gchar **out_mime_type,
+                                                GCancellable *cancellable,
+                                                GError **error);
+};
+
+GType          e_content_request_get_type              (void);
+gboolean       e_content_request_can_process_uri       (EContentRequest *request,
+                                                        const gchar *uri);
+gboolean       e_content_request_process_sync          (EContentRequest *request,
+                                                        const gchar *uri,
+                                                        GObject *requester,
+                                                        GInputStream **out_stream,
+                                                        gint64 *out_stream_length,
+                                                        gchar **out_mime_type,
+                                                        GCancellable *cancellable,
+                                                        GError **error);
+void           e_content_request_process               (EContentRequest *request,
+                                                        const gchar *uri,
+                                                        GObject *requester,
+                                                        GCancellable *cancellable,
+                                                        GAsyncReadyCallback callback,
+                                                        gpointer user_data);
+gboolean       e_content_request_process_finish        (EContentRequest *request,
+                                                        GAsyncResult *result,
+                                                        GInputStream **out_stream,
+                                                        gint64 *out_stream_length,
+                                                        gchar **out_mime_type,
+                                                        GError **error);
+
+G_END_DECLS
+
+#endif /* E_CONTENT_REQUEST_H */
diff --git a/e-util/e-file-request.c b/e-util/e-file-request.c
index f6b4ac2..8cdb18a 100644
--- a/e-util/e-file-request.c
+++ b/e-util/e-file-request.c
@@ -15,178 +15,124 @@
  *
  */
 
-#define LIBSOUP_USE_UNSTABLE_REQUEST_API
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
 
-#include "e-file-request.h"
+#include <stdio.h>
+#include <string.h>
 
 #include <libsoup/soup.h>
 
-#include <stdio.h>
-#include <string.h>
+#include "e-file-request.h"
 
 #define d(x)
 
-#define E_FILE_REQUEST_GET_PRIVATE(obj) \
-       (G_TYPE_INSTANCE_GET_PRIVATE \
-       ((obj), E_TYPE_FILE_REQUEST, EFileRequestPrivate))
-
 struct _EFileRequestPrivate {
-       gchar *content_type;
-       gint content_length;
+       gint dummy;
 };
 
-G_DEFINE_TYPE (EFileRequest, e_file_request, SOUP_TYPE_REQUEST)
-
-static void
-handle_file_request (GSimpleAsyncResult *res,
-                     GObject *object,
-                     GCancellable *cancellable)
-{
-       EFileRequest *request = E_FILE_REQUEST (object);
-       SoupURI *uri;
-       GInputStream *stream;
-       gchar *contents;
-       gsize length;
-
-       if (g_cancellable_is_cancelled (cancellable))
-               return;
-
-       uri = soup_request_get_uri (SOUP_REQUEST (request));
-
-       if (g_file_get_contents (uri->path, &contents, &length, NULL)) {
+static void e_file_request_content_request_init (EContentRequestInterface *iface);
 
-               request->priv->content_type =
-                       g_content_type_guess (uri->path, NULL, 0, NULL);
-               request->priv->content_length = length;
-
-               stream = g_memory_input_stream_new_from_data (
-                               contents, length, (GDestroyNotify) g_free);
-               g_simple_async_result_set_op_res_gpointer (res, stream, g_object_unref);
-       }
-}
-
-static void
-file_request_finalize (GObject *object)
-{
-       EFileRequest *request = E_FILE_REQUEST (object);
-
-       if (request->priv->content_type) {
-               g_free (request->priv->content_type);
-               request->priv->content_type = NULL;
-       }
-
-       G_OBJECT_CLASS (e_file_request_parent_class)->finalize (object);
-}
+G_DEFINE_TYPE_WITH_CODE (EFileRequest, e_file_request, G_TYPE_OBJECT,
+       G_IMPLEMENT_INTERFACE (E_TYPE_CONTENT_REQUEST, e_file_request_content_request_init))
 
 static gboolean
-file_request_check_uri (SoupRequest *request,
-                       SoupURI *uri,
-                       GError **error)
-{
-       return (strcmp (uri->scheme, "evo-file") == 0);
-}
-
-static void
-file_request_send_async (SoupRequest *request,
-                         GCancellable *cancellable,
-                         GAsyncReadyCallback callback,
-                         gpointer user_data)
+e_file_request_can_process_uri (EContentRequest *request,
+                               const gchar *uri)
 {
-       GSimpleAsyncResult *simple;
-
-       d (
-               SoupURI *soup_uri = soup_request_get_uri (request);
-               gchar *uri = soup_uri_to_string (soup_uri, FALSE);
-               printf ("received request for %s\n", uri);
-               g_free (uri);
-       );
-
-       /* WebKit won't allow us to load data through local file:// protocol
-        * when using "remote" mail:// protocol, so we have evo-file://
-        * which WebKit thinks it's remote, but in fact it behaves like
-        * oridnary file:// */
-
-       simple = g_simple_async_result_new (
-               G_OBJECT (request), callback, user_data,
-               file_request_send_async);
-
-       g_simple_async_result_set_check_cancellable (simple, cancellable);
-
-       g_simple_async_result_run_in_thread (
-               simple, handle_file_request,
-               G_PRIORITY_DEFAULT, cancellable);
+       g_return_val_if_fail (E_IS_FILE_REQUEST (request), FALSE);
+       g_return_val_if_fail (uri != NULL, FALSE);
 
-       g_object_unref (simple);
+       return g_ascii_strncasecmp (uri, "evo-file:", 9) == 0;
 }
 
-static GInputStream *
-file_request_send_finish (SoupRequest *request,
-                          GAsyncResult *result,
-                          GError **error)
+static gboolean
+e_file_request_process_sync (EContentRequest *request,
+                            const gchar *uri,
+                            GObject *requester,
+                            GInputStream **out_stream,
+                            gint64 *out_stream_length,
+                            gchar **out_mime_type,
+                            GCancellable *cancellable,
+                            GError **error)
 {
-       GSimpleAsyncResult *simple;
-       GInputStream *stream;
-
-       simple = G_SIMPLE_ASYNC_RESULT (result);
-       stream = g_simple_async_result_get_op_res_gpointer (simple);
-
-       /* Reset the stream before passing it back to webkit */
-       if (stream && G_IS_SEEKABLE (stream))
-               g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL);
-
-       if (!stream) /* We must always return something */
-               stream = g_memory_input_stream_new ();
-       else
-               g_object_ref (stream);
-
-       return stream;
-}
+       GFile *file;
+       GFileInputStream *file_input_stream;
+       GFileInfo *info;
+       goffset total_size;
+       SoupURI *suri;
+
+       g_return_val_if_fail (E_IS_FILE_REQUEST (request), FALSE);
+       g_return_val_if_fail (uri != NULL, FALSE);
+
+       if (g_cancellable_set_error_if_cancelled (cancellable, error))
+               return FALSE;
+
+       suri = soup_uri_new (uri);
+       g_return_val_if_fail (suri != NULL, FALSE);
+
+       file = g_file_new_for_path (suri->path);
+       file_input_stream = g_file_read (file, cancellable, error);
+
+       if (file_input_stream) {
+               total_size = -1;
+               info = g_file_input_stream_query_info (file_input_stream, G_FILE_ATTRIBUTE_STANDARD_SIZE, 
cancellable, NULL);
+               if (info) {
+                       if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE))
+                               total_size = g_file_info_get_size (info);
+                       g_object_unref (info);
+               }
+
+               if (total_size == -1) {
+                       info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_SIZE, 
G_FILE_QUERY_INFO_NONE, cancellable, NULL);
+                       if (info) {
+                               if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE))
+                                       total_size = g_file_info_get_size (info);
+                               g_object_unref (info);
+                       }
+               }
+       } else {
+               total_size = -1;
+       }
 
-static goffset
-file_request_get_content_length (SoupRequest *request)
-{
-       EFileRequest *efr = E_FILE_REQUEST (request);
+       if (file_input_stream) {
+               *out_stream = G_INPUT_STREAM (file_input_stream);
+               *out_stream_length = (gint64) total_size;
+               *out_mime_type = g_content_type_guess (suri->path, NULL, 0, NULL);
+       } else {
+               *out_stream = NULL;
+               *out_stream_length = (gint64) total_size;
+               *out_mime_type = NULL;
+       }
 
-       d (printf ("Content-Length: %d bytes\n", efr->priv->content_length));
+       g_object_unref (file);
+       soup_uri_free (suri);
 
-       return efr->priv->content_length;
+       return file_input_stream != NULL;
 }
 
-static const gchar *
-file_request_get_content_type (SoupRequest *request)
+static void
+e_file_request_content_request_init (EContentRequestInterface *iface)
 {
-       EFileRequest *efr = E_FILE_REQUEST (request);
-
-       d (printf ("Content-Type: %s\n", efr->priv->content_type));
-
-       return efr->priv->content_type;
+       iface->can_process_uri = e_file_request_can_process_uri;
+       iface->process_sync = e_file_request_process_sync;
 }
 
-static const gchar *data_schemes[] = { "evo-file", NULL };
-
 static void
 e_file_request_class_init (EFileRequestClass *class)
 {
-       GObjectClass *object_class;
-       SoupRequestClass *request_class;
-
        g_type_class_add_private (class, sizeof (EFileRequestPrivate));
-
-       object_class = G_OBJECT_CLASS (class);
-       object_class->finalize = file_request_finalize;
-
-       request_class = SOUP_REQUEST_CLASS (class);
-       request_class->schemes = data_schemes;
-       request_class->send_async = file_request_send_async;
-       request_class->send_finish = file_request_send_finish;
-       request_class->get_content_type = file_request_get_content_type;
-       request_class->get_content_length = file_request_get_content_length;
-       request_class->check_uri = file_request_check_uri;
 }
 
 static void
 e_file_request_init (EFileRequest *request)
 {
-       request->priv = E_FILE_REQUEST_GET_PRIVATE (request);
+       request->priv = G_TYPE_INSTANCE_GET_PRIVATE (request, E_TYPE_FILE_REQUEST, EFileRequestPrivate);
 }
 
+EContentRequest *
+e_file_request_new (void)
+{
+       return g_object_new (E_TYPE_FILE_REQUEST, NULL);
+}
diff --git a/e-util/e-file-request.h b/e-util/e-file-request.h
index ab46c9a..706309d 100644
--- a/e-util/e-file-request.h
+++ b/e-util/e-file-request.h
@@ -22,10 +22,7 @@
 #ifndef E_FILE_REQUEST_H
 #define E_FILE_REQUEST_H
 
-#define LIBSOUP_USE_UNSTABLE_REQUEST_API
-
-#include <libsoup/soup.h>
-#include <libsoup/soup-request.h>
+#include <e-util/e-content-request.h>
 
 /* Standard GObject macros */
 #define E_TYPE_FILE_REQUEST \
@@ -53,15 +50,17 @@ typedef struct _EFileRequestClass EFileRequestClass;
 typedef struct _EFileRequestPrivate EFileRequestPrivate;
 
 struct _EFileRequest {
-       SoupRequest parent;
+       GObject parent;
        EFileRequestPrivate *priv;
 };
 
 struct _EFileRequestClass {
-       SoupRequestClass parent;
+       GObjectClass parent;
 };
 
 GType          e_file_request_get_type         (void) G_GNUC_CONST;
+EContentRequest *
+               e_file_request_new              (void);
 
 G_END_DECLS
 
diff --git a/e-util/e-misc-utils.c b/e-util/e-misc-utils.c
index e9bbcfe..c985ccc 100644
--- a/e-util/e-misc-utils.c
+++ b/e-util/e-misc-utils.c
@@ -3326,3 +3326,19 @@ e_util_set_entry_issue_hint (GtkWidget *entry,
                gtk_entry_set_icon_tooltip_text (eentry, GTK_ENTRY_ICON_SECONDARY, NULL);
        }
 }
+
+static GThread *main_thread = NULL;
+
+void
+e_util_init_main_thread (GThread *thread)
+{
+       g_return_if_fail (main_thread == NULL);
+
+       main_thread = thread ? thread : g_thread_self ();
+}
+
+gboolean
+e_util_is_main_thread (GThread *thread)
+{
+       return thread ? thread == main_thread : g_thread_self () == main_thread;
+}
diff --git a/e-util/e-misc-utils.h b/e-util/e-misc-utils.h
index 931fa37..cb78a72 100644
--- a/e-util/e-misc-utils.h
+++ b/e-util/e-misc-utils.h
@@ -287,6 +287,9 @@ void                e_util_set_entry_issue_hint     (GtkWidget *entry,
 
 guint          e_util_normalize_font_size      (GtkWidget *widget,
                                                 gdouble font_size);
+void           e_util_init_main_thread         (GThread *thread);
+gboolean       e_util_is_main_thread           (GThread *thread);
+
 G_END_DECLS
 
 #endif /* E_MISC_UTILS_H */
diff --git a/e-util/e-stock-request.c b/e-util/e-stock-request.c
index 5d70fa3..f170909 100644
--- a/e-util/e-stock-request.c
+++ b/e-util/e-stock-request.c
@@ -15,56 +15,87 @@
  *
  */
 
-#define LIBSOUP_USE_UNSTABLE_REQUEST_API
-
-#include "e-stock-request.h"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
 
 #include <stdlib.h>
+#include <string.h>
+
 #include <gtk/gtk.h>
 #include <libsoup/soup.h>
 
-#include <string.h>
+#include <libedataserver/libedataserver.h>
 
-#define E_STOCK_REQUEST_GET_PRIVATE(obj) \
-       (G_TYPE_INSTANCE_GET_PRIVATE \
-       ((obj), E_TYPE_STOCK_REQUEST, EStockRequestPrivate))
+#include "e-misc-utils.h"
+#include "e-stock-request.h"
 
 struct _EStockRequestPrivate {
-       gchar *content_type;
-       gint content_length;
+       gint dummy;
 };
 
-static const gchar *data_schemes[] = { "gtk-stock", NULL };
+static void e_stock_request_content_request_init (EContentRequestInterface *iface);
 
-G_DEFINE_TYPE (EStockRequest, e_stock_request, SOUP_TYPE_REQUEST)
+G_DEFINE_TYPE_WITH_CODE (EStockRequest, e_stock_request, G_TYPE_OBJECT,
+       G_IMPLEMENT_INTERFACE (E_TYPE_CONTENT_REQUEST, e_stock_request_content_request_init))
 
 static gboolean
-handle_stock_request_idle_cb (gpointer user_data)
+e_stock_request_can_process_uri (EContentRequest *request,
+                                const gchar *uri)
 {
-       EStockRequestPrivate *priv;
-       GSimpleAsyncResult *simple;
-       GObject *object;
-       SoupURI *uri;
+       g_return_val_if_fail (E_IS_STOCK_REQUEST (request), FALSE);
+       g_return_val_if_fail (uri != NULL, FALSE);
+
+       return g_ascii_strncasecmp (uri, "gtk-stock:", 10) == 0;
+}
+
+typedef struct _StockIdleData
+{
+       EContentRequest *request;
+       const gchar *uri;
+       GObject *requester;
+       GInputStream **out_stream;
+       gint64 *out_stream_length;
+       gchar **out_mime_type;
+       GCancellable *cancellable;
+       GError **error;
+
+       gboolean success;
+       EFlag *flag;
+} StockIdleData;
+
+static gboolean
+process_stock_request_idle_cb (gpointer user_data)
+{
+       StockIdleData *sid = user_data;
+       SoupURI *suri;
        GHashTable *query = NULL;
        GtkStyleContext *context;
        GtkWidgetPath *path;
        GtkIconSet *icon_set;
        gssize size = GTK_ICON_SIZE_BUTTON;
        gchar *a_size;
-       gchar *buffer = NULL;
+       gchar *buffer = NULL, *mime_type = NULL;
        gsize buff_len = 0;
        GError *local_error = NULL;
 
-       simple = G_SIMPLE_ASYNC_RESULT (user_data);
+       g_return_val_if_fail (sid != NULL, FALSE);
+       g_return_val_if_fail (E_IS_STOCK_REQUEST (sid->request), FALSE);
+       g_return_val_if_fail (sid->uri != NULL, FALSE);
+       g_return_val_if_fail (sid->flag != NULL, FALSE);
+
+       if (g_cancellable_set_error_if_cancelled (sid->cancellable, sid->error)) {
+               sid->success = FALSE;
+               e_flag_set (sid->flag);
 
-       /* This returns a new reference. */
-       object = g_async_result_get_source_object (G_ASYNC_RESULT (simple));
+               return FALSE;
+       }
 
-       priv = E_STOCK_REQUEST_GET_PRIVATE (object);
+       suri = soup_uri_new (sid->uri);
+       g_return_val_if_fail (suri != NULL, FALSE);
 
-       uri = soup_request_get_uri (SOUP_REQUEST (object));
-       if (uri->query != NULL)
-               query = soup_form_decode (uri->query);
+       if (suri->query != NULL)
+               query = soup_form_decode (suri->query);
 
        if (query != NULL) {
                a_size = g_hash_table_lookup (query, "size");
@@ -81,7 +112,7 @@ handle_stock_request_idle_cb (gpointer user_data)
        gtk_style_context_set_path (context, path);
        gtk_widget_path_free (path);
 
-       icon_set = gtk_style_context_lookup_icon_set (context, uri->host);
+       icon_set = gtk_style_context_lookup_icon_set (context, suri->host);
        if (icon_set != NULL) {
                GdkPixbuf *pixbuf;
 
@@ -101,7 +132,7 @@ handle_stock_request_idle_cb (gpointer user_data)
                icon_theme = gtk_icon_theme_get_default ();
 
                icon_info = gtk_icon_theme_lookup_icon (
-                       icon_theme, uri->host, size,
+                       icon_theme, suri->host, size,
                        GTK_ICON_LOOKUP_USE_BUILTIN);
 
                /* Some icons can be missing in the theme */
@@ -113,9 +144,7 @@ handle_stock_request_idle_cb (gpointer user_data)
                                        buffer = NULL;
                                        buff_len = 0;
                                }
-                               priv->content_type =
-                                       g_content_type_guess (filename, NULL, 0, NULL);
-
+                               mime_type = g_content_type_guess (filename, NULL, 0, NULL);
                        } else {
                                GdkPixbuf *pixbuf;
 
@@ -137,148 +166,97 @@ handle_stock_request_idle_cb (gpointer user_data)
                ((buffer != NULL) && (local_error == NULL)) ||
                ((buffer == NULL) && (local_error != NULL)));
 
-       if (priv->content_type == NULL)
-               priv->content_type = g_strdup ("image/png");
-       priv->content_length = buff_len;
+       if (!mime_type)
+               mime_type = g_strdup ("image/png");
 
        if (buffer != NULL) {
-               GInputStream *stream;
-
-               stream = g_memory_input_stream_new_from_data (
-                       buffer, buff_len, (GDestroyNotify) g_free);
-               g_simple_async_result_set_op_res_gpointer (
-                       simple, g_object_ref (stream),
-                       (GDestroyNotify) g_object_unref);
-               g_object_unref (stream);
-       }
-
-       if (local_error != NULL)
-               g_simple_async_result_take_error (simple, local_error);
-
-       g_simple_async_result_complete_in_idle (simple);
+               *sid->out_stream = g_memory_input_stream_new_from_data (buffer, buff_len, g_free);;
+               *sid->out_stream_length = buff_len;
+               *sid->out_mime_type = mime_type;
 
-       g_object_unref (context);
-       g_object_unref (object);
+               sid->success = TRUE;
+       } else {
+               g_free (mime_type);
 
-       return FALSE;
-}
+               if (local_error)
+                       g_propagate_error (sid->error, local_error);
 
-static void
-stock_request_finalize (GObject *object)
-{
-       EStockRequestPrivate *priv;
+               sid->success = FALSE;
+       }
 
-       priv = E_STOCK_REQUEST_GET_PRIVATE (object);
+       g_object_unref (context);
 
-       g_free (priv->content_type);
+       e_flag_set (sid->flag);
 
-       /* Chain up to parent's finalize() method. */
-       G_OBJECT_CLASS (e_stock_request_parent_class)->finalize (object);
+       return FALSE;
 }
 
 static gboolean
-stock_request_check_uri (SoupRequest *request,
-                         SoupURI *uri,
-                         GError **error)
+e_stock_request_process_sync (EContentRequest *request,
+                             const gchar *uri,
+                             GObject *requester,
+                             GInputStream **out_stream,
+                             gint64 *out_stream_length,
+                             gchar **out_mime_type,
+                             GCancellable *cancellable,
+                             GError **error)
 {
-       return (strcmp (uri->scheme, "gtk-stock") == 0);
-}
-
-static void
-stock_request_send_async (SoupRequest *request,
-                          GCancellable *cancellable,
-                          GAsyncReadyCallback callback,
-                          gpointer user_data)
-{
-       GSimpleAsyncResult *simple;
-
-       simple = g_simple_async_result_new (
-               G_OBJECT (request), callback, user_data,
-               stock_request_send_async);
-
-       g_simple_async_result_set_check_cancellable (simple, cancellable);
-
-       /* Need to run this operation in an idle callback rather
-        * than a worker thread, since we're making all kinds of
-        * GdkPixbuf/GTK+ calls. */
-       g_idle_add_full (
-               G_PRIORITY_HIGH_IDLE,
-               handle_stock_request_idle_cb,
-               g_object_ref (simple),
-               (GDestroyNotify) g_object_unref);
-
-       g_object_unref (simple);
-}
-
-static GInputStream *
-stock_request_send_finish (SoupRequest *request,
-                           GAsyncResult *result,
-                           GError **error)
-{
-       GSimpleAsyncResult *simple;
-       GInputStream *stream;
-
-       simple = G_SIMPLE_ASYNC_RESULT (result);
-       stream = g_simple_async_result_get_op_res_gpointer (simple);
-
-       if (g_simple_async_result_propagate_error (simple, error))
-               return NULL;
-
-       /* Reset the stream before passing it back to WebKit. */
-       if (G_IS_SEEKABLE (stream))
-               g_seekable_seek (
-                       G_SEEKABLE (stream), 0,
-                       G_SEEK_SET, NULL, NULL);
-
-       if (stream != NULL)
-               return g_object_ref (stream);
-
-       return g_memory_input_stream_new ();
-}
-
-static goffset
-stock_request_get_content_length (SoupRequest *request)
-{
-       EStockRequestPrivate *priv;
+       StockIdleData sid;
+
+       g_return_val_if_fail (E_IS_STOCK_REQUEST (request), FALSE);
+       g_return_val_if_fail (uri != NULL, FALSE);
+
+       sid.request = request;
+       sid.uri = uri;
+       sid.requester = requester;
+       sid.out_stream = out_stream;
+       sid.out_stream_length = out_stream_length;
+       sid.out_mime_type = out_mime_type;
+       sid.cancellable = cancellable;
+       sid.error = error;
+       sid.flag = e_flag_new ();
+       sid.success = FALSE;
+
+       if (e_util_is_main_thread (NULL)) {
+               process_stock_request_idle_cb (&sid);
+       } else {
+               /* Need to run this operation in an idle callback rather
+                * than a worker thread, since we're making all kinds of
+                * GdkPixbuf/GTK+ calls. */
+               g_idle_add_full (
+                       G_PRIORITY_HIGH_IDLE,
+                       process_stock_request_idle_cb,
+                       &sid, NULL);
+
+               e_flag_wait (sid.flag);
+       }
 
-       priv = E_STOCK_REQUEST_GET_PRIVATE (request);
+       e_flag_free (sid.flag);
 
-       return priv->content_length;
+       return sid.success;
 }
 
-static const gchar *
-stock_request_get_content_type (SoupRequest *request)
+static void
+e_stock_request_content_request_init (EContentRequestInterface *iface)
 {
-       EStockRequestPrivate *priv;
-
-       priv = E_STOCK_REQUEST_GET_PRIVATE (request);
-
-       return priv->content_type;
+       iface->can_process_uri = e_stock_request_can_process_uri;
+       iface->process_sync = e_stock_request_process_sync;
 }
 
 static void
 e_stock_request_class_init (EStockRequestClass *class)
 {
-       GObjectClass *object_class;
-       SoupRequestClass *request_class;
-
        g_type_class_add_private (class, sizeof (EStockRequestPrivate));
-
-       object_class = G_OBJECT_CLASS (class);
-       object_class->finalize = stock_request_finalize;
-
-       request_class = SOUP_REQUEST_CLASS (class);
-       request_class->schemes = data_schemes;
-       request_class->check_uri = stock_request_check_uri;
-       request_class->send_async = stock_request_send_async;
-       request_class->send_finish = stock_request_send_finish;
-       request_class->get_content_length = stock_request_get_content_length;
-       request_class->get_content_type = stock_request_get_content_type;
 }
 
 static void
 e_stock_request_init (EStockRequest *request)
 {
-       request->priv = E_STOCK_REQUEST_GET_PRIVATE (request);
+       request->priv = G_TYPE_INSTANCE_GET_PRIVATE (request, E_TYPE_STOCK_REQUEST, EStockRequestPrivate);
 }
 
+EContentRequest *
+e_stock_request_new (void)
+{
+       return g_object_new (E_TYPE_STOCK_REQUEST, NULL);
+}
diff --git a/e-util/e-stock-request.h b/e-util/e-stock-request.h
index be6222b..09800d0 100644
--- a/e-util/e-stock-request.h
+++ b/e-util/e-stock-request.h
@@ -22,10 +22,7 @@
 #ifndef E_STOCK_REQUEST_H
 #define E_STOCK_REQUEST_H
 
-#define LIBSOUP_USE_UNSTABLE_REQUEST_API
-
-#include <libsoup/soup.h>
-#include <libsoup/soup-request.h>
+#include <e-util/e-content-request.h>
 
 /* Standard GObject macros */
 #define E_TYPE_STOCK_REQUEST \
@@ -53,15 +50,17 @@ typedef struct _EStockRequestClass EStockRequestClass;
 typedef struct _EStockRequestPrivate EStockRequestPrivate;
 
 struct _EStockRequest {
-       SoupRequest parent;
+       GObject parent;
        EStockRequestPrivate *priv;
 };
 
 struct _EStockRequestClass {
-       SoupRequestClass parent;
+       GObjectClass parent;
 };
 
 GType          e_stock_request_get_type        (void) G_GNUC_CONST;
+EContentRequest *
+               e_stock_request_new             (void);
 
 G_END_DECLS
 
diff --git a/e-util/e-util.h b/e-util/e-util.h
index 72230dc..209a0f1 100644
--- a/e-util/e-util.h
+++ b/e-util/e-util.h
@@ -86,6 +86,7 @@
 #include <e-util/e-config.h>
 #include <e-util/e-conflict-search-selector.h>
 #include <e-util/e-contact-store.h>
+#include <e-util/e-content-request.h>
 #include <e-util/e-data-capture.h>
 #include <e-util/e-dateedit.h>
 #include <e-util/e-datetime-format.h>
diff --git a/e-util/e-web-view.c b/e-util/e-web-view.c
index 1d8fa54..6efd68e 100644
--- a/e-util/e-web-view.c
+++ b/e-util/e-web-view.c
@@ -1000,13 +1000,93 @@ web_view_finalize (GObject *object)
        G_OBJECT_CLASS (e_web_view_parent_class)->finalize (object);
 }
 
+
+static void
+web_view_uri_request_done_cb (GObject *source_object,
+                             GAsyncResult *result,
+                             gpointer user_data)
+{
+       WebKitURISchemeRequest *request = user_data;
+       GInputStream *stream = NULL;
+       gint64 stream_length = -1;
+       gchar *mime_type = NULL;
+       GError *error = NULL;
+
+       g_return_if_fail (E_IS_CONTENT_REQUEST (source_object));
+       g_return_if_fail (WEBKIT_IS_URI_SCHEME_REQUEST (request));
+
+       if (!e_content_request_process_finish (E_CONTENT_REQUEST (source_object),
+               result, &stream, &stream_length, &mime_type, &error)) {
+               webkit_uri_scheme_request_finish_error (request, error);
+       } else {
+               webkit_uri_scheme_request_finish (request, stream, stream_length, mime_type);
+
+               g_clear_object (&stream);
+               g_free (mime_type);
+       }
+
+       g_object_unref (request);
+}
+
+static void
+web_view_process_uri_request_cb (WebKitURISchemeRequest *request,
+                                gpointer user_data)
+{
+       EContentRequest *content_request = user_data;
+       const gchar *uri;
+       GObject *requester;
+
+       g_return_if_fail (WEBKIT_IS_URI_SCHEME_REQUEST (request));
+       g_return_if_fail (E_IS_CONTENT_REQUEST (content_request));
+
+       uri = webkit_uri_scheme_request_get_uri (request);
+       requester = G_OBJECT (webkit_uri_scheme_request_get_web_view (request));
+
+       g_return_if_fail (e_content_request_can_process_uri (content_request, uri));
+
+       e_content_request_process (content_request, uri, requester, NULL,
+               web_view_uri_request_done_cb, g_object_ref (request));
+}
+
+/* 'scheme' is like "file", not "file:" */
+void
+e_web_view_register_content_request_for_scheme (EWebView *web_view,
+                                               const gchar *scheme,
+                                               EContentRequest *content_request)
+{
+       WebKitWebContext *web_context;
+
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+       g_return_if_fail (E_IS_CONTENT_REQUEST (content_request));
+       g_return_if_fail (scheme != NULL);
+
+       web_context = webkit_web_view_get_context (WEBKIT_WEB_VIEW (web_view));
+
+       webkit_web_context_register_uri_scheme (web_context, scheme, web_view_process_uri_request_cb,
+               g_object_ref (content_request), g_object_unref);
+}
+
 static void
 web_view_initialize (WebKitWebView *web_view)
 {
+       WebKitWebContext *web_context;
+       EContentRequest *content_request;
        const gchar *id = "org.gnome.settings-daemon.plugins.xsettings";
        GSettings *settings = NULL, *font_settings;
        GSettingsSchema *settings_schema;
 
+       web_context = webkit_web_view_get_context (web_view);
+
+       webkit_web_context_set_cache_model (web_context, WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
+
+       content_request = e_file_request_new ();
+       e_web_view_register_content_request_for_scheme (E_WEB_VIEW (web_view), "evo-file", content_request);
+       g_object_unref (content_request);
+
+       content_request = e_stock_request_new ();
+       e_web_view_register_content_request_for_scheme (E_WEB_VIEW (web_view), "gtk-stock", content_request);
+       g_object_unref (content_request);
+
        /* Optional schema */
        settings_schema = g_settings_schema_source_lookup (
                g_settings_schema_source_get_default (), id, FALSE);
@@ -1700,216 +1780,6 @@ e_web_view_test_change_and_update_fonts_cb (EWebView *web_view,
 }
 
 static void
-web_view_process_uri_scheme_finished_cb (EWebView *web_view,
-                                         GAsyncResult *result,
-                                         WebKitURISchemeRequest *request)
-{
-       GError *error = NULL;
-
-       if (!g_task_propagate_boolean (G_TASK (result), &error)) {
-               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-                       g_warning ("URI %s cannot be processed: %s",
-                               webkit_uri_scheme_request_get_uri (request),
-                               error ? error->message : "Unknown error");
-               }
-               g_object_unref (request);
-               if (error)
-                       g_error_free (error);
-       }
-}
-
-static void
-web_view_process_file_uri_scheme_request (GTask *task,
-                                          gpointer source_object,
-                                          gpointer task_data,
-                                          GCancellable *cancellable)
-{
-       gboolean ret_val = FALSE;
-       const gchar *uri;
-       gchar *content = NULL;
-       gchar *content_type = NULL;
-       gchar *filename = NULL;
-       GInputStream *stream;
-       gsize length = 0;
-       GError *error = NULL;
-       WebKitURISchemeRequest *request = WEBKIT_URI_SCHEME_REQUEST (task_data);
-
-       uri = webkit_uri_scheme_request_get_uri (request);
-
-       filename = g_filename_from_uri (strstr (uri, "file"), NULL, &error);
-       if (!filename)
-               goto out;
-
-       if (!g_file_get_contents (filename, &content, &length, &error))
-               goto out;
-
-       content_type = g_content_type_guess (filename, NULL, 0, NULL);
-
-       stream = g_memory_input_stream_new_from_data (content, length, g_free);
-
-       webkit_uri_scheme_request_finish (request, stream, length, content_type);
-
-       ret_val = TRUE;
- out:
-       g_free (content_type);
-       g_free (content);
-       g_free (filename);
-
-       if (ret_val)
-               g_object_unref (request);
-
-       if (error)
-               g_task_return_error (task, error);
-       else
-               g_task_return_boolean (task, ret_val);
-}
-
-static void
-web_view_file_uri_scheme_appeared_cb (WebKitURISchemeRequest *request)
-{
-       EWebView *web_view;
-       GTask *task;
-
-       web_view = E_WEB_VIEW (webkit_uri_scheme_request_get_web_view (request));
-
-       task = g_task_new (
-               web_view, NULL,
-               (GAsyncReadyCallback) web_view_process_uri_scheme_finished_cb,
-               request);
-
-       g_task_set_task_data (task, g_object_ref (request), NULL);
-       g_task_run_in_thread (task, web_view_process_file_uri_scheme_request);
-
-       g_object_unref (task);
-}
-
-static void
-web_view_gtk_stock_uri_scheme_appeared_cb (WebKitURISchemeRequest *request)
-{
-       SoupURI *uri;
-       GHashTable *query = NULL;
-       GtkStyleContext *context;
-       GtkWidgetPath *path;
-       GtkIconSet *icon_set;
-       gssize size = GTK_ICON_SIZE_BUTTON;
-       gchar *a_size;
-       gchar *buffer = NULL;
-       gchar *content_type = NULL;
-       gsize buff_len = 0;
-       GError *local_error = NULL;
-
-       uri = soup_uri_new (webkit_uri_scheme_request_get_uri (request));
-
-       if (uri && uri->query)
-               query = soup_form_decode (uri->query);
-
-       if (query) {
-               a_size = g_hash_table_lookup (query, "size");
-               if (a_size != NULL)
-                       size = atoi (a_size);
-               g_hash_table_destroy (query);
-       }
-
-       /* Try style context first */
-       context = gtk_style_context_new ();
-       path = gtk_widget_path_new ();
-       gtk_widget_path_append_type (path, GTK_TYPE_WINDOW);
-       gtk_widget_path_append_type (path, GTK_TYPE_BUTTON);
-       gtk_style_context_set_path (context, path);
-       gtk_widget_path_free (path);
-
-       icon_set = gtk_style_context_lookup_icon_set (context, uri->host);
-       if (icon_set != NULL) {
-               GdkPixbuf *pixbuf;
-
-               pixbuf = gtk_icon_set_render_icon_pixbuf (
-                       icon_set, context, size);
-               gdk_pixbuf_save_to_buffer (
-                       pixbuf, &buffer, &buff_len,
-                       "png", &local_error, NULL);
-               g_object_unref (pixbuf);
-       /* Fallback to icon theme */
-       } else {
-               GtkIconTheme *icon_theme;
-               GtkIconInfo *icon_info;
-               const gchar *filename;
-
-               icon_theme = gtk_icon_theme_get_default ();
-
-               icon_info = gtk_icon_theme_lookup_icon (
-                       icon_theme, uri->host, size,
-                       GTK_ICON_LOOKUP_USE_BUILTIN);
-
-               filename = gtk_icon_info_get_filename (icon_info);
-               if (filename != NULL) {
-                       g_file_get_contents (
-                               filename, &buffer, &buff_len, &local_error);
-                       content_type =
-                               g_content_type_guess (filename, NULL, 0, NULL);
-
-               } else {
-                       GdkPixbuf *pixbuf;
-
-                       pixbuf = gtk_icon_info_get_builtin_pixbuf (icon_info);
-                       if (pixbuf != NULL) {
-                               gdk_pixbuf_save_to_buffer (
-                                       pixbuf, &buffer, &buff_len,
-                                       "png", &local_error, NULL);
-                               g_object_unref (pixbuf);
-                       }
-               }
-
-               gtk_icon_info_free (icon_info);
-       }
-
-       /* Sanity check */
-       g_return_if_fail (
-               ((buffer != NULL) && (local_error == NULL)) ||
-               ((buffer == NULL) && (local_error != NULL)));
-
-       if (!content_type)
-               content_type = g_strdup ("image/png");
-
-       if (buffer != NULL) {
-               GInputStream *stream;
-
-               stream = g_memory_input_stream_new_from_data (
-                       buffer, buff_len, (GDestroyNotify) g_free);
-
-               webkit_uri_scheme_request_finish (
-                       request, stream, buff_len, content_type);
-
-               g_object_unref (stream);
-       }
-
-       g_object_unref (context);
-       g_free (content_type);
-}
-
-static void
-web_view_initialize_web_context (void)
-{
-       WebKitWebContext *web_context = webkit_web_context_get_default ();
-
-       webkit_web_context_set_cache_model (
-               web_context, WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
-
-       webkit_web_context_register_uri_scheme (
-               web_context,
-               "evo-file",
-               (WebKitURISchemeRequestCallback) web_view_file_uri_scheme_appeared_cb,
-               NULL,
-               NULL);
-
-       webkit_web_context_register_uri_scheme (
-               web_context,
-               "gtk-stock",
-               (WebKitURISchemeRequestCallback) web_view_gtk_stock_uri_scheme_appeared_cb,
-               NULL,
-               NULL);
-}
-
-static void
 web_view_toplevel_event_after_cb (GtkWidget *widget,
                                  GdkEvent *event,
                                  EWebView *web_view)
@@ -1968,8 +1838,6 @@ e_web_view_class_init (EWebViewClass *class)
 
        g_type_class_add_private (class, sizeof (EWebViewPrivate));
 
-       web_view_initialize_web_context ();
-
        object_class = G_OBJECT_CLASS (class);
        object_class->constructor = web_view_constructor;
        object_class->set_property = web_view_set_property;
diff --git a/e-util/e-web-view.h b/e-util/e-web-view.h
index fb54a90..0b7e4c4 100644
--- a/e-util/e-web-view.h
+++ b/e-util/e-web-view.h
@@ -30,6 +30,7 @@
 
 #include <webkit2/webkit2.h>
 #include <e-util/e-activity.h>
+#include <e-util/e-content-request.h>
 
 /* Standard GObject macros */
 #define E_TYPE_WEB_VIEW \
@@ -113,6 +114,10 @@ GtkWidget *        e_web_view_new                  (void);
 WebKitSettings *
                e_web_view_get_default_webkit_settings
                                                (void);
+void           e_web_view_register_content_request_for_scheme
+                                               (EWebView *web_view,
+                                                const gchar *scheme,
+                                                EContentRequest *content_request);
 void           e_web_view_update_fonts_settings
                                                (GSettings *font_settings,
                                                 GSettings *aliasing_settings,
diff --git a/mail/Makefile.am b/mail/Makefile.am
index 06aa259..acf784f 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -52,6 +52,7 @@ libevolution_mail_la_CPPFLAGS =                               \
        $(NULL)
 
 mailinclude_HEADERS =                                  \
+       e-cid-request.h                                 \
        e-http-request.h                                \
        e-mail.h                                        \
        e-mail-account-manager.h                        \
@@ -135,6 +136,7 @@ mailinclude_HEADERS =                                       \
        message-list.h
 
 libevolution_mail_la_SOURCES =                         \
+       e-cid-request.c                                 \
        e-http-request.c                                \
        e-mail-account-manager.c                        \
        e-mail-account-store.c                          \
diff --git a/mail/e-cid-request.c b/mail/e-cid-request.c
new file mode 100644
index 0000000..9d82398
--- /dev/null
+++ b/mail/e-cid-request.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "e-mail-display.h"
+#include "e-cid-request.h"
+
+struct _ECidRequestPrivate {
+       gint dummy;
+};
+
+static void e_cid_request_content_request_init (EContentRequestInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (ECidRequest, e_cid_request, G_TYPE_OBJECT,
+       G_IMPLEMENT_INTERFACE (E_TYPE_CONTENT_REQUEST, e_cid_request_content_request_init))
+
+static gboolean
+e_cid_request_can_process_uri (EContentRequest *request,
+                               const gchar *uri)
+{
+       g_return_val_if_fail (E_IS_CID_REQUEST (request), FALSE);
+       g_return_val_if_fail (uri != NULL, FALSE);
+
+       return g_ascii_strncasecmp (uri, "cid:", 4) == 0;
+}
+
+static gboolean
+e_cid_request_process_sync (EContentRequest *request,
+                           const gchar *uri,
+                           GObject *requester,
+                           GInputStream **out_stream,
+                           gint64 *out_stream_length,
+                           gchar **out_mime_type,
+                           GCancellable *cancellable,
+                           GError **error)
+{
+       EMailDisplay *display;
+       EMailPartList *part_list;
+       EMailPart *part;
+       const gchar *mime_type;
+       GByteArray *byte_array;
+       CamelStream *output_stream;
+       CamelDataWrapper *dw;
+       CamelMimePart *mime_part;
+       gboolean success = FALSE;
+
+       g_return_val_if_fail (E_IS_CID_REQUEST (request), FALSE);
+       g_return_val_if_fail (uri != NULL, FALSE);
+
+       if (g_cancellable_set_error_if_cancelled (cancellable, error))
+               return FALSE;
+
+       if (!E_IS_MAIL_DISPLAY (requester))
+               return FALSE;
+
+       display = E_MAIL_DISPLAY (requester);
+
+       part_list = e_mail_display_get_part_list (display);
+       if (!part_list)
+               return FALSE;
+
+       part = e_mail_part_list_ref_part (part_list, uri);
+       if (!part)
+               return FALSE;
+
+       mime_type = e_mail_part_get_mime_type (part);
+       mime_part = e_mail_part_ref_mime_part (part);
+       dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
+
+       g_return_val_if_fail (dw != NULL, FALSE);
+
+       byte_array = g_byte_array_new ();
+       output_stream = camel_stream_mem_new ();
+
+       /* We retain ownership of the byte array. */
+       camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (output_stream), byte_array);
+
+       if (camel_data_wrapper_decode_to_stream_sync (dw, output_stream, cancellable, error)) {
+               GBytes *bytes;
+
+               bytes = g_byte_array_free_to_bytes (byte_array);
+
+               success = TRUE;
+
+               *out_stream = g_memory_input_stream_new_from_bytes (bytes);
+               *out_stream_length = g_bytes_get_size (bytes);
+               *out_mime_type = g_strdup (mime_type);
+
+               g_bytes_unref (bytes);
+       }
+
+       g_object_unref (mime_part);
+       g_object_unref (part);
+
+       return success;
+}
+
+static void
+e_cid_request_content_request_init (EContentRequestInterface *iface)
+{
+       iface->can_process_uri = e_cid_request_can_process_uri;
+       iface->process_sync = e_cid_request_process_sync;
+}
+
+static void
+e_cid_request_class_init (ECidRequestClass *class)
+{
+       g_type_class_add_private (class, sizeof (ECidRequestPrivate));
+}
+
+static void
+e_cid_request_init (ECidRequest *request)
+{
+       request->priv = G_TYPE_INSTANCE_GET_PRIVATE (request, E_TYPE_CID_REQUEST, ECidRequestPrivate);
+}
+
+EContentRequest *
+e_cid_request_new (void)
+{
+       return g_object_new (E_TYPE_CID_REQUEST, NULL);
+}
diff --git a/mail/e-cid-request.h b/mail/e-cid-request.h
new file mode 100644
index 0000000..0ed6e4b
--- /dev/null
+++ b/mail/e-cid-request.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef E_CID_REQUEST_H
+#define E_CID_REQUEST_H
+
+#include <e-util/e-util.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CID_REQUEST \
+       (e_cid_request_get_type ())
+#define E_CID_REQUEST(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_CID_REQUEST, ECidRequest))
+#define E_CID_REQUEST_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_CID_REQUEST, ECidRequestClass))
+#define E_IS_CID_REQUEST(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_CID_REQUEST))
+#define E_IS_CID_REQUEST_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_CID_REQUEST))
+#define E_CID_REQUEST_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_CID_REQUEST, ECidRequestClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECidRequest ECidRequest;
+typedef struct _ECidRequestClass ECidRequestClass;
+typedef struct _ECidRequestPrivate ECidRequestPrivate;
+
+struct _ECidRequest {
+       GObject parent;
+       ECidRequestPrivate *priv;
+};
+
+struct _ECidRequestClass {
+       GObjectClass parent;
+};
+
+GType          e_cid_request_get_type          (void) G_GNUC_CONST;
+EContentRequest *
+               e_cid_request_new               (void);
+
+G_END_DECLS
+
+#endif /* E_CID_REQUEST_H */
diff --git a/mail/e-http-request.c b/mail/e-http-request.c
index 403a454..5af3de6 100644
--- a/mail/e-http-request.c
+++ b/mail/e-http-request.c
@@ -15,9 +15,10 @@
  *
  */
 
-#include "e-http-request.h"
-
+#ifdef HAVE_CONFIG_H
 #include <config.h>
+#endif
+
 #include <string.h>
 
 #define LIBSOUP_USE_UNSTABLE_REQUEST_API
@@ -35,19 +36,29 @@
 #include <shell/e-shell.h>
 
 #include "e-mail-ui-session.h"
+#include "e-http-request.h"
 
 #define d(x)
 
-#define E_HTTP_REQUEST_GET_PRIVATE(obj) \
-       (G_TYPE_INSTANCE_GET_PRIVATE \
-       ((obj), E_TYPE_HTTP_REQUEST, EHTTPRequestPrivate))
-
 struct _EHTTPRequestPrivate {
-       gchar *content_type;
-       gint content_length;
+       gint dummy;
 };
 
-G_DEFINE_TYPE (EHTTPRequest, e_http_request, SOUP_TYPE_REQUEST)
+static void e_http_request_content_request_init (EContentRequestInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EHTTPRequest, e_http_request, G_TYPE_OBJECT,
+       G_IMPLEMENT_INTERFACE (E_TYPE_CONTENT_REQUEST, e_http_request_content_request_init))
+
+static gboolean
+e_http_request_can_process_uri (EContentRequest *request,
+                               const gchar *uri)
+{
+       g_return_val_if_fail (E_IS_HTTP_REQUEST (request), FALSE);
+       g_return_val_if_fail (uri != NULL, FALSE);
+
+       return g_ascii_strncasecmp (uri, "evo-http:", 9) == 0 ||
+              g_ascii_strncasecmp (uri, "evo-https:", 10) == 0;
+}
 
 static gssize
 copy_stream_to_stream (GIOStream *file_io_stream,
@@ -162,16 +173,18 @@ http_request_cancelled_cb (GCancellable *cancellable,
        soup_session_abort (session);
 }
 
-static void
-handle_http_request (GSimpleAsyncResult *res,
-                     GObject *source_object,
-                     GCancellable *cancellable)
+static gboolean
+e_http_request_process_sync (EContentRequest *request,
+                            const gchar *uri,
+                            GObject *requester,
+                            GInputStream **out_stream,
+                            gint64 *out_stream_length,
+                            gchar **out_mime_type,
+                            GCancellable *cancellable,
+                            GError **error)
 {
-       EHTTPRequestPrivate *priv;
        SoupURI *soup_uri;
-       SoupRequest *soup_request;
-       SoupSession *soup_session;
-       gchar *evo_uri, *uri;
+       gchar *evo_uri, *use_uri;
        gchar *mail_uri = NULL;
        GInputStream *stream;
        gboolean force_load_images = FALSE;
@@ -183,15 +196,16 @@ handle_http_request (GSimpleAsyncResult *res,
        CamelDataCache *cache;
        GIOStream *cache_stream;
        gint uri_len;
+       gboolean success = FALSE;
 
-       if (g_cancellable_is_cancelled (cancellable))
-               return;
+       g_return_val_if_fail (E_IS_HTTP_REQUEST (request), FALSE);
+       g_return_val_if_fail (uri != NULL, FALSE);
 
-       priv = E_HTTP_REQUEST_GET_PRIVATE (source_object);
+       if (g_cancellable_set_error_if_cancelled (cancellable, error))
+               return FALSE;
 
-       soup_request = SOUP_REQUEST (source_object);
-       soup_session = soup_request_get_session (soup_request);
-       soup_uri = soup_request_get_uri (soup_request);
+       soup_uri = soup_uri_new (uri);
+       g_return_val_if_fail (soup_uri != NULL, FALSE);
 
        /* Remove the __evo-mail query */
        soup_query = soup_uri_get_query (soup_uri);
@@ -224,24 +238,26 @@ handle_http_request (GSimpleAsyncResult *res,
 
        /* Remove the "evo-" prefix from scheme */
        uri_len = (evo_uri != NULL) ? strlen (evo_uri) : 0;
-       uri = NULL;
+       use_uri = NULL;
        if (evo_uri != NULL && (uri_len > 5)) {
 
                /* Remove trailing "?" if there is no URI query */
                if (evo_uri[uri_len - 1] == '?') {
-                       uri = g_strndup (evo_uri + 4, uri_len - 5);
+                       use_uri = g_strndup (evo_uri + 4, uri_len - 5);
                } else {
-                       uri = g_strdup (evo_uri + 4);
+                       use_uri = g_strdup (evo_uri + 4);
                }
                g_free (evo_uri);
        }
 
-       g_return_if_fail (uri && *uri);
+       g_return_val_if_fail (use_uri && *use_uri, FALSE);
+
+       *out_stream_length = -1;
 
        /* Use MD5 hash of the URI as a filname of the resourec cache file.
         * We were previously using the URI as a filename but the URI is
         * sometimes too long for a filename. */
-       uri_md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, uri, -1);
+       uri_md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, use_uri, -1);
 
        /* Open Evolution's cache */
        user_cache_dir = e_get_user_cache_dir ();
@@ -256,17 +272,15 @@ handle_http_request (GSimpleAsyncResult *res,
 
                stream = g_memory_input_stream_new ();
 
-               len = copy_stream_to_stream (
-                       cache_stream,
-                       G_MEMORY_INPUT_STREAM (stream), cancellable);
-               priv->content_length = len;
+               len = copy_stream_to_stream (cache_stream, G_MEMORY_INPUT_STREAM (stream), cancellable);
+               *out_stream_length = len;
 
                g_object_unref (cache_stream);
 
                /* When succesfully read some data from cache then
                 * get mimetype and return the stream to WebKit.
                 * Otherwise try to fetch the resource again from the network. */
-               if ((len != -1) && (priv->content_length > 0)) {
+               if (len != -1 && *out_stream_length > 0) {
                        GFile *file;
                        GFileInfo *info;
                        gchar *path;
@@ -279,13 +293,12 @@ handle_http_request (GSimpleAsyncResult *res,
                                0, cancellable, NULL);
 
                        if (info) {
-                               priv->content_type = g_strdup (
-                                       g_file_info_get_content_type (info));
+                               *out_mime_type = g_strdup (g_file_info_get_content_type (info));
 
                                d (
                                        printf ("'%s' found in cache (%d bytes, %s)\n",
-                                       uri, priv->content_length,
-                                       priv->content_type));
+                                       use_uri, (gint) *out_stream_length,
+                                       *out_mime_type));
                        }
 
                        g_clear_object (&info);
@@ -293,12 +306,12 @@ handle_http_request (GSimpleAsyncResult *res,
                        g_free (path);
 
                        /* Set result and quit the thread */
-                       g_simple_async_result_set_op_res_gpointer (
-                               res, stream, g_object_unref);
+                       *out_stream = stream;
+                       success = TRUE;
 
                        goto cleanup;
                } else {
-                       d (printf ("Failed to load '%s' from cache.\n", uri));
+                       d (printf ("Failed to load '%s' from cache.\n", use_uri));
                        g_object_unref (stream);
                }
        }
@@ -332,7 +345,6 @@ handle_http_request (GSimpleAsyncResult *res,
                        CamelInternetAddress *addr;
                        CamelMimeMessage *message;
                        gboolean known_address = FALSE;
-                       GError *error = NULL;
 
                        shell_backend =
                                e_shell_get_backend_by_name (shell, "mail");
@@ -342,14 +354,13 @@ handle_http_request (GSimpleAsyncResult *res,
                        message = e_mail_part_list_get_message (part_list);
                        addr = camel_mime_message_get_from (message);
 
-                       e_mail_ui_session_check_known_address_sync (
+                       if (!e_mail_ui_session_check_known_address_sync (
                                E_MAIL_UI_SESSION (session),
                                addr, FALSE, cancellable,
-                               &known_address, &error);
-
-                       if (error != NULL) {
-                               g_warning ("%s: %s", G_STRFUNC, error->message);
-                               g_error_free (error);
+                               &known_address, error)) {
+                               g_object_unref (part_list);
+                               g_free (decoded_uri);
+                               goto cleanup;
                        }
 
                        if (known_address)
@@ -363,20 +374,19 @@ handle_http_request (GSimpleAsyncResult *res,
 
        if ((image_policy == E_IMAGE_LOADING_POLICY_ALWAYS) ||
            force_load_images) {
-
+               ESource *proxy_source;
                SoupSession *temp_session;
                SoupMessage *message;
                GIOStream *cache_stream;
-               GError *error;
                GMainContext *context;
                gulong cancelled_id = 0;
 
-               if (g_cancellable_is_cancelled (cancellable))
+               if (g_cancellable_set_error_if_cancelled (cancellable, error))
                        goto cleanup;
 
-               message = soup_message_new (SOUP_METHOD_GET, uri);
+               message = soup_message_new (SOUP_METHOD_GET, use_uri);
                if (!message) {
-                       g_debug ("%s: Skipping invalid URI '%s'", G_STRFUNC, uri);
+                       g_debug ("%s: Skipping invalid URI '%s'", G_STRFUNC, use_uri);
                        goto cleanup;
                }
 
@@ -386,12 +396,16 @@ handle_http_request (GSimpleAsyncResult *res,
                temp_session = soup_session_new_with_options (
                        SOUP_SESSION_TIMEOUT, 90, NULL);
 
-               e_binding_bind_property (
-                       soup_session, "proxy-resolver",
-                       temp_session, "proxy-resolver",
-                       G_BINDING_SYNC_CREATE);
+               proxy_source = e_source_registry_ref_builtin_proxy (e_shell_get_registry (shell));
+
+               g_object_set (
+                       temp_session,
+                       SOUP_SESSION_PROXY_RESOLVER,
+                       G_PROXY_RESOLVER (proxy_source),
+                       NULL);
+
+               g_object_unref (proxy_source);
 
-               message = soup_message_new (SOUP_METHOD_GET, uri);
                soup_message_headers_append (
                        message->request_headers,
                        "User-Agent", "Evolution/" VERSION);
@@ -405,7 +419,7 @@ handle_http_request (GSimpleAsyncResult *res,
                        g_cancellable_disconnect (cancellable, cancelled_id);
 
                if (!SOUP_STATUS_IS_SUCCESSFUL (message->status_code)) {
-                       g_debug ("Failed to request %s (code %d)", uri, message->status_code);
+                       g_debug ("Failed to request %s (code %d)", use_uri, message->status_code);
                        g_object_unref (message);
                        g_object_unref (temp_session);
                        g_main_context_unref (context);
@@ -413,55 +427,40 @@ handle_http_request (GSimpleAsyncResult *res,
                }
 
                /* Write the response body to cache */
-               error = NULL;
                cache_stream = camel_data_cache_add (
-                       cache, "http", uri_md5, &error);
-               if (error != NULL) {
-                       g_warning (
-                               "Failed to create cache file for '%s': %s",
-                               uri, error->message);
-                       g_clear_error (&error);
-               } else {
+                       cache, "http", uri_md5, error);
+               if (cache_stream) {
                        GOutputStream *output_stream;
 
                        output_stream =
                                g_io_stream_get_output_stream (cache_stream);
 
-                       g_output_stream_write_all (
+                       success = g_output_stream_write_all (
                                output_stream,
                                message->response_body->data,
                                message->response_body->length,
-                               NULL, cancellable, &error);
+                               NULL, cancellable, error);
 
                        g_io_stream_close (cache_stream, NULL, NULL);
                        g_object_unref (cache_stream);
 
-                       if (error != NULL) {
-                               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
-                                       g_warning (
-                                               "Failed to write data to cache stream: %s",
-                                               error->message);
-                               g_clear_error (&error);
-                               g_object_unref (message);
-                               g_object_unref (temp_session);
-                               g_main_context_unref (context);
-                               goto cleanup;
+                       if (success) {
+                               /* Send the response body to WebKit */
+                               stream = g_memory_input_stream_new_from_data (
+                                       g_memdup (
+                                               message->response_body->data,
+                                               message->response_body->length),
+                                       message->response_body->length,
+                                       (GDestroyNotify) g_free);
+
+                               *out_stream = stream;
+                               *out_stream_length = message->response_body->length;
+                               *out_mime_type = g_strdup (
+                                       soup_message_headers_get_content_type (
+                                               message->response_headers, NULL));
                        }
                }
 
-               /* Send the response body to WebKit */
-               stream = g_memory_input_stream_new_from_data (
-                       g_memdup (
-                               message->response_body->data,
-                               message->response_body->length),
-                       message->response_body->length,
-                       (GDestroyNotify) g_free);
-
-               priv->content_length = message->response_body->length;
-               priv->content_type = g_strdup (
-                       soup_message_headers_get_content_type (
-                               message->response_headers, NULL));
-
                g_object_unref (message);
                g_object_unref (temp_session);
                g_main_context_unref (context);
@@ -470,150 +469,42 @@ handle_http_request (GSimpleAsyncResult *res,
                        "Content-Type: %s\n"
                        "Content-Length: %d bytes\n"
                        "URI MD5: %s:\n",
-                       uri, priv->content_type,
-                       priv->content_length, uri_md5));
-
-               g_simple_async_result_set_op_res_gpointer (res, stream, g_object_unref);
-
-               goto cleanup;
+                       use_uri, *out_mime_type ? *out_mime_type : "[null]",
+                       (gint) *out_stream_length, uri_md5));
        }
 
-cleanup:
+ cleanup:
        g_clear_object (&cache);
 
-       g_free (uri);
+       g_free (use_uri);
        g_free (uri_md5);
        g_free (mail_uri);
-}
-
-static void
-http_request_finalize (GObject *object)
-{
-       EHTTPRequest *request = E_HTTP_REQUEST (object);
-
-       if (request->priv->content_type) {
-               g_free (request->priv->content_type);
-               request->priv->content_type = NULL;
-       }
-
-       G_OBJECT_CLASS (e_http_request_parent_class)->finalize (object);
-}
+       soup_uri_free (soup_uri);
 
-static gboolean
-http_request_check_uri (SoupRequest *request,
-                        SoupURI *uri,
-                        GError **error)
-{
-       return ((strcmp (uri->scheme, "evo-http") == 0) ||
-               (strcmp (uri->scheme, "evo-https") == 0));
+       return success;
 }
 
 static void
-http_request_send_async (SoupRequest *request,
-                         GCancellable *cancellable,
-                         GAsyncReadyCallback callback,
-                         gpointer user_data)
+e_http_request_content_request_init (EContentRequestInterface *iface)
 {
-       GSimpleAsyncResult *simple;
-
-       d ({
-               const gchar *soup_query;
-               SoupURI *uri;
-
-               uri = soup_request_get_uri (request);
-               soup_query = soup_uri_get_query (uri);
-
-               if (soup_query) {
-                       gchar *uri_str;
-                       GHashTable *query;
-
-                       query = soup_form_decode (soup_uri_get_query (uri));
-                       uri_str = soup_uri_to_string (uri, FALSE);
-                       printf ("received request for %s\n", uri_str);
-                       g_free (uri_str);
-                       g_hash_table_destroy (query);
-               }
-       });
-
-       simple = g_simple_async_result_new (
-               G_OBJECT (request), callback,
-               user_data, http_request_send_async);
-
-       g_simple_async_result_set_check_cancellable (simple, cancellable);
-
-       e_util_run_simple_async_result_in_thread (
-               simple, handle_http_request,
-               cancellable);
-
-       g_object_unref (simple);
+       iface->can_process_uri = e_http_request_can_process_uri;
+       iface->process_sync = e_http_request_process_sync;
 }
 
-static GInputStream *
-http_request_send_finish (SoupRequest *request,
-                          GAsyncResult *result,
-                          GError **error)
-{
-       GInputStream *stream;
-
-       stream = g_simple_async_result_get_op_res_gpointer (
-               G_SIMPLE_ASYNC_RESULT (result));
-
-       /* Reset the stream before passing it back to webkit */
-       if (stream && G_IS_SEEKABLE (stream))
-               g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL);
-
-       if (!stream) /* We must always return something */
-               stream = g_memory_input_stream_new ();
-       else
-               g_object_ref (stream);
-
-       return stream;
-}
-
-static goffset
-http_request_get_content_length (SoupRequest *request)
-{
-       EHTTPRequest *efr = E_HTTP_REQUEST (request);
-
-       d (printf ("Content-Length: %d bytes\n", efr->priv->content_length));
-       return efr->priv->content_length;
-}
-
-static const gchar *
-http_request_get_content_type (SoupRequest *request)
-{
-       EHTTPRequest *efr = E_HTTP_REQUEST (request);
-
-       d (printf ("Content-Type: %s\n", efr->priv->content_type));
-
-       return efr->priv->content_type;
-}
-
-static const gchar *data_schemes[] = { "evo-http", "evo-https", NULL };
-
 static void
 e_http_request_class_init (EHTTPRequestClass *class)
 {
-       GObjectClass *object_class;
-       SoupRequestClass *request_class;
-
        g_type_class_add_private (class, sizeof (EHTTPRequestPrivate));
-
-       object_class = G_OBJECT_CLASS (class);
-       object_class->finalize = http_request_finalize;
-
-       request_class = SOUP_REQUEST_CLASS (class);
-       request_class->schemes = data_schemes;
-       request_class->send_async = http_request_send_async;
-       request_class->send_finish = http_request_send_finish;
-       request_class->get_content_type = http_request_get_content_type;
-       request_class->get_content_length = http_request_get_content_length;
-       request_class->check_uri = http_request_check_uri;
 }
 
 static void
 e_http_request_init (EHTTPRequest *request)
 {
-       request->priv = E_HTTP_REQUEST_GET_PRIVATE (request);
+       request->priv = G_TYPE_INSTANCE_GET_PRIVATE (request, E_TYPE_HTTP_REQUEST, EHTTPRequestPrivate);
 }
 
+EContentRequest *
+e_http_request_new (void)
+{
+       return g_object_new (E_TYPE_HTTP_REQUEST, NULL);
+}
diff --git a/mail/e-http-request.h b/mail/e-http-request.h
index de4cb23..bdbf009 100644
--- a/mail/e-http-request.h
+++ b/mail/e-http-request.h
@@ -18,10 +18,7 @@
 #ifndef E_HTTP_REQUEST_H
 #define E_HTTP_REQUEST_H
 
-#define LIBSOUP_USE_UNSTABLE_REQUEST_API
-
-#include <libsoup/soup.h>
-#include <libsoup/soup-request.h>
+#include <e-util/e-util.h>
 
 /* Standard GObject macros */
 #define E_TYPE_HTTP_REQUEST \
@@ -49,15 +46,18 @@ typedef struct _EHTTPRequestClass EHTTPRequestClass;
 typedef struct _EHTTPRequestPrivate EHTTPRequestPrivate;
 
 struct _EHTTPRequest {
-       SoupRequest parent;
+       GObject parent;
        EHTTPRequestPrivate *priv;
 };
 
 struct _EHTTPRequestClass {
-       SoupRequestClass parent;
+       GObjectClass parent;
 };
 
 GType          e_http_request_get_type         (void) G_GNUC_CONST;
+EContentRequest *
+               e_http_request_new              (void);
+
 
 G_END_DECLS
 
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index 4718775..b821887 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -34,6 +34,7 @@
 #include <em-format/e-mail-part-attachment.h>
 #include <em-format/e-mail-part-utils.h>
 
+#include "e-cid-request.h"
 #include "e-http-request.h"
 #include "e-mail-display-popup-extension.h"
 #include "e-mail-notes.h"
@@ -1447,6 +1448,9 @@ mail_display_web_view_initialize (WebKitWebView *web_view)
 static void
 mail_display_constructed (GObject *object)
 {
+       EContentRequest *content_request;
+       EWebView *web_view;
+
        e_extensible_load_extensions (E_EXTENSIBLE (object));
 
        /* Chain up to parent's constructed() method. */
@@ -1454,7 +1458,22 @@ mail_display_constructed (GObject *object)
 
        mail_display_web_view_initialize (WEBKIT_WEB_VIEW (object));
 
-       e_web_view_update_fonts (E_WEB_VIEW (object));
+       web_view = E_WEB_VIEW (object);
+
+       e_web_view_update_fonts (web_view);
+
+       content_request = e_http_request_new ();
+       e_web_view_register_content_request_for_scheme (web_view, "evo-http", content_request);
+       e_web_view_register_content_request_for_scheme (web_view, "evo-https", content_request);
+       g_object_unref (content_request);
+
+       content_request = e_mail_request_new ();
+       e_web_view_register_content_request_for_scheme (web_view, "mail", content_request);
+       g_object_unref (content_request);
+
+       content_request = e_cid_request_new ();
+       e_web_view_register_content_request_for_scheme (web_view, "cid", content_request);
+       g_object_unref (content_request);
 }
 
 static void
@@ -1735,812 +1754,6 @@ e_mail_display_test_change_and_update_fonts_cb (EMailDisplay *mail_display,
 }
 
 static void
-mail_display_process_uri_scheme_finished_cb (EMailDisplay *display,
-                                             GAsyncResult *result,
-                                             WebKitURISchemeRequest *request)
-{
-       GError *error = NULL;
-
-       if (!g_task_propagate_boolean (G_TASK (result), &error)) {
-               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-                       g_warning ("URI %s cannot be processed: %s",
-                               webkit_uri_scheme_request_get_uri (request),
-                               error ? error->message : "Unknown error");
-               }
-               g_object_unref (request);
-               if (error)
-                       g_error_free (error);
-       }
-}
-
-static void
-mail_display_cid_uri_scheme_appeared_cb (WebKitURISchemeRequest *request)
-{
-       EMailDisplay *display;
-       EMailPartList *part_list;
-       EMailPart *part;
-       GInputStream *stream;
-       const gchar *uri;
-       const gchar *mime_type;
-       GByteArray *byte_array;
-       CamelStream *output_stream;
-       GCancellable *cancellable = NULL;
-       CamelDataWrapper *dw;
-       CamelMimePart *mime_part;
-
-       display = E_MAIL_DISPLAY (webkit_uri_scheme_request_get_web_view (request));
-
-       g_return_if_fail (E_IS_MAIL_DISPLAY (display));
-
-       part_list = e_mail_display_get_part_list (display);
-       uri = webkit_uri_scheme_request_get_uri (request);
-       part = e_mail_part_list_ref_part (part_list, uri);
-       mime_type = e_mail_part_get_mime_type (part);
-       mime_part = e_mail_part_ref_mime_part (part);
-       dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
-
-       g_return_if_fail (dw);
-
-       byte_array = g_byte_array_new ();
-       output_stream = camel_stream_mem_new ();
-
-       /* We retain ownership of the byte array. */
-       camel_stream_mem_set_byte_array (
-               CAMEL_STREAM_MEM (output_stream), byte_array);
-
-       camel_data_wrapper_decode_to_stream_sync (
-               dw, output_stream, cancellable, NULL);
-
-       stream = g_memory_input_stream_new_from_bytes (
-               g_byte_array_free_to_bytes (byte_array));
-
-       webkit_uri_scheme_request_finish (request, stream, -1, mime_type);
-
-       g_object_unref (mime_part);
-       g_object_unref (stream);
-       g_object_unref (part);
-}
-
-static gssize
-copy_stream_to_stream (GIOStream *file_io_stream,
-                       GMemoryInputStream *output,
-                       GCancellable *cancellable)
-{
-       GInputStream *input_stream;
-       gchar *buff;
-       gssize read_len = 0;
-       gssize total_len = 0;
-       const gsize buff_size = 4096;
-
-       g_seekable_seek (
-               G_SEEKABLE (file_io_stream), 0,
-               G_SEEK_SET, cancellable, NULL);
-
-       input_stream = g_io_stream_get_input_stream (file_io_stream);
-
-       buff = g_malloc (buff_size);
-       read_len = g_input_stream_read (
-               input_stream, buff, buff_size, cancellable, NULL);
-       while (read_len > 0) {
-               g_memory_input_stream_add_data (
-                       output, buff, read_len, g_free);
-
-               total_len += read_len;
-
-               buff = g_malloc (buff_size);
-               read_len = g_input_stream_read (
-                       input_stream, buff, buff_size, cancellable, NULL);
-       }
-
-       /* Free the last unused buffer */
-       g_free (buff);
-
-       return total_len;
-}
-
-static void
-redirect_handler (SoupMessage *msg,
-                  gpointer user_data)
-{
-       if (SOUP_STATUS_IS_REDIRECTION (msg->status_code)) {
-               SoupSession *soup_session = user_data;
-               SoupURI *new_uri;
-               const gchar *new_loc;
-
-               new_loc = soup_message_headers_get_list (msg->response_headers, "Location");
-               if (!new_loc)
-                       return;
-
-               new_uri = soup_uri_new_with_base (soup_message_get_uri (msg), new_loc);
-               if (!new_uri) {
-                       soup_message_set_status_full (
-                               msg,
-                               SOUP_STATUS_MALFORMED,
-                               "Invalid Redirect URL");
-                       return;
-               }
-
-               soup_message_set_uri (msg, new_uri);
-               soup_session_requeue_message (soup_session, msg);
-
-               soup_uri_free (new_uri);
-       }
-}
-
-static void
-send_and_handle_redirection (SoupSession *session,
-                             SoupMessage *message,
-                             gchar **new_location)
-{
-       gchar *old_uri = NULL;
-
-       g_return_if_fail (message != NULL);
-
-       if (new_location) {
-               old_uri = soup_uri_to_string (soup_message_get_uri (message), FALSE);
-       }
-
-       soup_message_set_flags (message, SOUP_MESSAGE_NO_REDIRECT);
-       soup_message_add_header_handler (
-               message, "got_body", "Location",
-               G_CALLBACK (redirect_handler), session);
-       soup_message_headers_append (message->request_headers, "Connection", "close");
-       soup_session_send_message (session, message);
-
-       if (new_location) {
-               gchar *new_loc = soup_uri_to_string (soup_message_get_uri (message), FALSE);
-
-               if (new_loc && old_uri && !g_str_equal (new_loc, old_uri)) {
-                       *new_location = new_loc;
-               } else {
-                       g_free (new_loc);
-               }
-       }
-
-       g_free (old_uri);
-}
-
-static void
-web_view_process_http_uri_scheme_request (GTask *task,
-                                          gpointer source_object,
-                                          gpointer task_data,
-                                          GCancellable *cancellable)
-{
-       SoupURI *soup_uri;
-       gchar *evo_uri, *uri;
-       gchar *mail_uri;
-       const gchar *user_cache_dir;
-       const gchar *content_type;
-       GInputStream *stream = NULL;
-       gboolean force_load_images = FALSE;
-       gboolean ret_val = FALSE;
-       EImageLoadingPolicy image_policy;
-       gchar *uri_md5;
-       EShell *shell;
-       GSettings *settings;
-       CamelDataCache *cache;
-       GIOStream *cache_stream;
-       GHashTable *query;
-       gint uri_len;
-       WebKitURISchemeRequest *request = WEBKIT_URI_SCHEME_REQUEST (task_data);
-
-       /* Remove the __evo-mail query */
-       soup_uri = soup_uri_new (webkit_uri_scheme_request_get_uri (request));
-
-       if (!soup_uri_get_query (soup_uri)) {
-               g_task_return_boolean (task, FALSE);
-               soup_uri_free (soup_uri);
-               return;
-       }
-
-       query = soup_form_decode (soup_uri_get_query (soup_uri));
-       mail_uri = g_hash_table_lookup (query, "__evo-mail");
-       if (mail_uri)
-               mail_uri = g_strdup (mail_uri);
-
-       g_hash_table_remove (query, "__evo-mail");
-
-       /* Remove __evo-load-images if present (and in such case set
-        * force_load_images to TRUE) */
-       force_load_images = g_hash_table_remove (query, "__evo-load-images");
-
-       soup_uri_set_query_from_form (soup_uri, query);
-       g_hash_table_unref (query);
-
-       evo_uri = soup_uri_to_string (soup_uri, FALSE);
-
-       if (camel_debug_start ("emformat:requests")) {
-               printf ("%s: looking for '%s'\n", G_STRFUNC, evo_uri);
-               camel_debug_end ();
-       }
-
-       /* Remove the "evo-" prefix from scheme */
-       uri_len = strlen (evo_uri);
-       uri = NULL;
-       if (evo_uri && (uri_len > 5)) {
-               /* Remove trailing "?" if there is no URI query */
-               if (evo_uri[uri_len - 1] == '?') {
-                       uri = g_strndup (evo_uri + 4, uri_len - 5);
-               } else {
-                       uri = g_strdup (evo_uri + 4);
-               }
-               g_free (evo_uri);
-       }
-
-       if (!uri || !*uri)
-               goto cleanup;
-
-       /* Use MD5 hash of the URI as a filname of the resourec cache file.
-        * We were previously using the URI as a filename but the URI is
-        * sometimes too long for a filename. */
-       uri_md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, uri, -1);
-
-       /* Open Evolution's cache */
-       user_cache_dir = e_get_user_cache_dir ();
-       cache = camel_data_cache_new (user_cache_dir, NULL);
-       camel_data_cache_set_expire_age (cache, 24 * 60 * 60);
-       camel_data_cache_set_expire_access (cache, 2 * 60 * 60);
-
-       /* Found item in cache! */
-       cache_stream = camel_data_cache_get (cache, "http", uri_md5, NULL);
-       if (cache_stream)
-               goto process;
-
-       /* If the item is not in the cache and Evolution is in offline mode then
-        * quit regardless any image loading policy */
-       shell = e_shell_get_default ();
-       if (!e_shell_get_online (shell)) {
-               goto cleanup;
-       }
-
-       settings = e_util_ref_settings ("org.gnome.evolution.mail");
-       image_policy = g_settings_get_enum (settings, "image-loading-policy");
-       g_object_unref (settings);
-
-       /* Item not found in cache, but image loading policy allows us to fetch
-        * it from the interwebs */
-       if (!force_load_images && mail_uri &&
-           (image_policy == E_IMAGE_LOADING_POLICY_SOMETIMES)) {
-               CamelObjectBag *registry;
-               gchar *decoded_uri;
-               EMailPartList *part_list;
-
-               registry = e_mail_part_list_get_registry ();
-               decoded_uri = soup_uri_decode (mail_uri);
-
-               part_list = camel_object_bag_get (registry, decoded_uri);
-               if (part_list) {
-                       EShellBackend *shell_backend;
-                       EMailBackend *backend;
-                       EMailSession *session;
-                       CamelInternetAddress *addr;
-                       CamelMimeMessage *message;
-                       gboolean known_address = FALSE;
-                       GError *error = NULL;
-
-                       shell_backend =
-                               e_shell_get_backend_by_name (shell, "mail");
-                       backend = E_MAIL_BACKEND (shell_backend);
-                       session = e_mail_backend_get_session (backend);
-
-                       message = e_mail_part_list_get_message (part_list);
-                       addr = camel_mime_message_get_from (message);
-
-                       e_mail_ui_session_check_known_address_sync (
-                               E_MAIL_UI_SESSION (session),
-                               addr, FALSE, cancellable,
-                               &known_address, &error);
-
-                       if (error != NULL) {
-                               g_warning ("%s: %s", G_STRFUNC, error->message);
-                               g_error_free (error);
-                       }
-
-                       if (known_address)
-                               force_load_images = TRUE;
-
-                       g_object_unref (part_list);
-               }
-
-               g_free (decoded_uri);
-       }
-
-       if ((image_policy == E_IMAGE_LOADING_POLICY_ALWAYS) ||
-           force_load_images) {
-
-               SoupSession *temp_session;
-               SoupMessage *message;
-               GIOStream *cache_stream;
-               GError *error;
-               GMainContext *context;
-
-               message = soup_message_new (SOUP_METHOD_GET, uri);
-               if (!message) {
-                       g_debug ("%s: Skipping invalid URI '%s'", G_STRFUNC, uri);
-                       goto cleanup;
-               }
-
-               context = g_main_context_new ();
-               g_main_context_push_thread_default (context);
-
-               temp_session = soup_session_new_with_options (
-                       SOUP_SESSION_TIMEOUT, 90, NULL);
-#if 0
-/* FIXME WK2 */
-               e_binding_bind_property (
-                       soup_session, "proxy-resolver",
-                       temp_session, "proxy-resolver",
-                       G_BINDING_SYNC_CREATE);
-
-#endif
-               soup_message_headers_append (
-                       message->request_headers, "User-Agent", "Evolution/" VERSION);
-/* FIXME WK2
-               send_and_handle_redirection (session, message, NULL);*/
-               send_and_handle_redirection (temp_session, message, NULL);
-
-               if (!SOUP_STATUS_IS_SUCCESSFUL (message->status_code)) {
-                       g_warning ("Failed to request %s (code %d)", uri, message->status_code);
-                       goto cleanup;
-               }
-
-               /* Write the response body to cache */
-               error = NULL;
-               cache_stream = camel_data_cache_add (cache, "http", uri_md5, &error);
-               if (error != NULL) {
-                       g_warning (
-                               "Failed to create cache file for '%s': %s",
-                               uri, error->message);
-                       g_clear_error (&error);
-               } else {
-                       GOutputStream *output_stream;
-
-                       output_stream =
-                               g_io_stream_get_output_stream (cache_stream);
-
-                       g_output_stream_write_all (
-                               output_stream,
-                               message->response_body->data,
-                               message->response_body->length,
-                               NULL, cancellable, &error);
-
-                       g_io_stream_close (cache_stream, NULL, NULL);
-                       g_object_unref (cache_stream);
-
-                       if (error != NULL) {
-                               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
-                                       g_warning (
-                                               "Failed to write data to cache stream: %s",
-                                               error->message);
-                               g_clear_error (&error);
-                               g_object_unref (message);
-                               g_object_unref (temp_session);
-                               g_main_context_unref (context);
-                               goto cleanup;
-                       }
-               }
-
-               g_object_unref (message);
-/* FIXME WK2
-               g_object_unref (session);*/
-               g_object_unref (temp_session);
-       }
-
- process:
-       if (cache_stream) {
-               gssize len;
-
-               stream = g_memory_input_stream_new ();
-
-               len = copy_stream_to_stream (
-                       cache_stream,
-                       G_MEMORY_INPUT_STREAM (stream), cancellable);
-
-               g_io_stream_close (cache_stream, NULL, NULL);
-               g_object_unref (cache_stream);
-
-               /* When succesfully read some data from cache then
-                * get mimetype and return the stream to WebKit.
-                * Otherwise try to fetch the resource again from the network. */
-               if (len > 0) {
-                       GFile *file;
-                       GFileInfo *info;
-                       gchar *path;
-
-                       path = camel_data_cache_get_filename (cache, "http", uri_md5);
-                       file = g_file_new_for_path (path);
-
-                       info = g_file_query_info (
-                               file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
-                               0, cancellable, NULL);
-
-                       content_type = g_file_info_get_content_type (info);
-
-                       /* FIXME WK2 */
-                       webkit_uri_scheme_request_finish (
-                               request, stream, len, content_type);
-
-                       ret_val = TRUE;
-
-                       g_object_unref (request);
-                       g_object_unref (stream);
-
-                       d (
-                               printf ("'%s' found in cache (%d bytes, %s)\n",
-                               uri, len, content_type));
-
-                       g_object_unref (info);
-                       g_object_unref (file);
-                       g_free (path);
-               } else {
-                       d (printf ("Failed to load '%s' from cache.\n", uri));
-               }
-       }
- cleanup:
-       if (cache)
-               g_clear_object (&cache);
-
-       if (soup_uri)
-               soup_uri_free (soup_uri);
-
-       g_free (uri);
-       g_free (uri_md5);
-       g_free (mail_uri);
-
-       g_task_return_boolean (task, ret_val);
-}
-
-static void
-mail_display_http_uri_scheme_appeared_cb (WebKitURISchemeRequest *request)
-{
-       EMailDisplay *display;
-       GTask *task;
-       GCancellable *cancellable;
-
-       display = E_MAIL_DISPLAY (webkit_uri_scheme_request_get_web_view (request));
-
-       g_return_if_fail (E_IS_MAIL_DISPLAY (display));
-
-       cancellable = g_cancellable_new ();
-
-       task = g_task_new (
-               display, cancellable,
-               (GAsyncReadyCallback) mail_display_process_uri_scheme_finished_cb,
-               request);
-
-       g_task_set_task_data (task, g_object_ref (request), NULL);
-       g_task_run_in_thread (task, web_view_process_http_uri_scheme_request);
-
-       g_object_unref (task);
-       g_object_unref (cancellable);
-}
-
-static void
-mail_display_process_mail_uri_scheme_request (GTask *task,
-                                              gpointer source_object,
-                                              gpointer task_data,
-                                              GCancellable *cancellable)
-{
-       GInputStream *input_stream = NULL;
-       EMailFormatter *formatter;
-       EMailPartList *part_list;
-       GOutputStream *output_stream;
-       GHashTable *query;
-       const gchar *val, *uri;
-       const gchar *default_charset, *charset;
-       SoupURI *soup_uri;
-       EMailFormatterContext context = { 0 };
-       EMailDisplay *display = E_MAIL_DISPLAY (source_object);
-       WebKitURISchemeRequest *request = WEBKIT_URI_SCHEME_REQUEST (task_data);
-       GBytes *bytes;
-
-       uri = webkit_uri_scheme_request_get_uri (request);
-
-       part_list = display->priv->part_list;
-
-       if (camel_debug_start ("emformat:requests")) {
-               printf ("%s: found part-list %p for full_uri '%s'\n", G_STRFUNC, part_list, uri);
-               camel_debug_end ();
-       }
-
-       if (!part_list) {
-               g_task_return_boolean (task, FALSE);
-               return;
-       }
-
-       soup_uri = soup_uri_new (uri);
-       if (!soup_uri || !soup_uri->query) {
-               if (soup_uri)
-                       soup_uri_free (soup_uri);
-               g_task_return_boolean (task, FALSE);
-               return;
-       }
-       query = soup_form_decode (soup_uri->query);
-
-       val = g_hash_table_lookup (query, "headers_collapsed");
-       if (val && atoi (val) == 1)
-               context.flags |= E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED;
-
-       val = g_hash_table_lookup (query, "headers_collapsable");
-       if (val && atoi (val) == 1)
-               context.flags |= E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSABLE;
-
-       val = g_hash_table_lookup (query, "mode");
-       if (val)
-               context.mode = atoi (val);
-
-       default_charset = g_hash_table_lookup (query, "formatter_default_charset");
-       charset = g_hash_table_lookup (query, "formatter_charset");
-
-       context.part_list = g_object_ref (part_list);
-       context.uri = g_strdup (uri);
-
-       formatter = display->priv->formatter;
-
-       if (default_charset && *default_charset != '\0')
-               e_mail_formatter_set_default_charset (formatter, default_charset);
-       if (charset && *charset != '\0')
-               e_mail_formatter_set_charset (formatter, charset);
-
-       output_stream = g_memory_output_stream_new_resizable ();
-
-       val = g_hash_table_lookup (query, "part_id");
-       if (val) {
-               EMailPart *part;
-               const gchar *mime_type;
-               gchar *part_id;
-
-               part_id = soup_uri_decode (val);
-               part = e_mail_part_list_ref_part (part_list, part_id);
-               if (!part) {
-                       if (camel_debug_start ("emformat:requests")) {
-                               printf ("%s: part with id '%s' not found\n", G_STRFUNC, val);
-                               camel_debug_end ();
-                       }
-
-                       g_free (part_id);
-                       goto no_part;
-               }
-               g_free (part_id);
-
-               mime_type = g_hash_table_lookup (query, "mime_type");
-
-               if (context.mode == E_MAIL_FORMATTER_MODE_SOURCE)
-                       mime_type = "application/vnd.evolution.source";
-
-               if (context.mode == E_MAIL_FORMATTER_MODE_CID) {
-                       CamelDataWrapper *dw;
-                       CamelMimePart *mime_part;
-
-                       mime_part = e_mail_part_ref_mime_part (part);
-                       dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
-                       if (!dw)
-                               goto no_part;
-
-                       camel_data_wrapper_decode_to_output_stream_sync (
-                               dw, output_stream, cancellable, NULL);
-
-                       g_object_unref (mime_part);
-               } else {
-                       if (!mime_type)
-                               mime_type = e_mail_part_get_mime_type (part);
-
-                       e_mail_formatter_format_as (
-                               formatter, &context, part,
-                               output_stream, mime_type,
-                               cancellable);
-               }
-
-               g_object_unref (part);
-       } else {
-               e_mail_formatter_format_sync (
-                       formatter, part_list, output_stream,
-                       context.flags, context.mode, cancellable);
-       }
-
- no_part:
-       g_clear_object (&context.part_list);
-
-       g_output_stream_close (output_stream, NULL, NULL);
-
-       bytes = g_memory_output_stream_steal_as_bytes (
-               G_MEMORY_OUTPUT_STREAM (output_stream));
-
-       if (g_bytes_get_size (bytes) == 0) {
-               gchar *data;
-
-               g_bytes_unref (bytes);
-
-               data = g_strdup_printf (
-                       "<p align='center'>%s</p>",
-                       _("The message has no text content."));
-
-               /* Takes ownership of the string. */
-               bytes = g_bytes_new_take (
-                       data, strlen (data) + 1);
-       }
-
-       input_stream =
-               g_memory_input_stream_new_from_bytes (bytes);
-
-       webkit_uri_scheme_request_finish (request, input_stream, -1, "text/html; charset=UTF-8");
-
-       g_object_unref (input_stream);
-       g_object_unref (output_stream);
-
-       if (query)
-               g_hash_table_destroy (query);
-
-       if (soup_uri)
-               soup_uri_free (soup_uri);
-
-       g_task_return_boolean (task, TRUE);
-}
-
-static GInputStream *
-get_empty_image_stream (void)
-{
-       GdkPixbuf *pixbuf;
-       gchar *buffer;
-       gsize length;
-
-       pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
-       gdk_pixbuf_fill (pixbuf, 0x00000000); /* transparent black */
-       gdk_pixbuf_save_to_buffer (pixbuf, &buffer, &length, "png", NULL, NULL);
-       g_object_unref (pixbuf);
-
-       return g_memory_input_stream_new_from_data (buffer, length, g_free);
-}
-
-static void
-mail_display_process_contact_photo_uri_scheme_request (GTask *task,
-                                                       gpointer source_object,
-                                                       gpointer task_data,
-                                                       GCancellable *cancellable)
-{
-       EShell *shell;
-       EShellBackend *shell_backend;
-       EMailBackend *mail_backend;
-       EMailSession *mail_session;
-       EPhotoCache *photo_cache;
-       CamelInternetAddress *cia;
-       GInputStream *stream = NULL;
-       const gchar *uri;
-       const gchar *email_address;
-       const gchar *escaped_string;
-       gchar *unescaped_string;
-       GError *error = NULL;
-       SoupURI *soup_uri;
-       GHashTable *uri_query;
-       WebKitURISchemeRequest *request = WEBKIT_URI_SCHEME_REQUEST (task_data);
-
-       /* XXX Is this really the only way to obtain
-        *     the mail session instance from here? */
-       shell = e_shell_get_default ();
-       shell_backend = e_shell_get_backend_by_name (shell, "mail");
-       mail_backend = E_MAIL_BACKEND (shell_backend);
-       mail_session = e_mail_backend_get_session (mail_backend);
-
-       photo_cache = e_mail_ui_session_get_photo_cache (
-               E_MAIL_UI_SESSION (mail_session));
-
-       uri = webkit_uri_scheme_request_get_uri (request);
-
-       soup_uri = soup_uri_new (uri);
-       if (!soup_uri || !soup_uri->query)
-               goto exit;
-
-       uri_query = soup_form_decode (soup_uri->query);
-       escaped_string = g_hash_table_lookup (uri_query, "mailaddr");
-       if (escaped_string == NULL || *escaped_string == '\0')
-               goto exit;
-
-       cia = camel_internet_address_new ();
-
-       unescaped_string = g_uri_unescape_string (escaped_string, NULL);
-       camel_address_decode (CAMEL_ADDRESS (cia), unescaped_string);
-       g_free (unescaped_string);
-
-       if (camel_internet_address_get (cia, 0, NULL, &email_address))
-               e_photo_cache_get_photo_sync (
-                       photo_cache, email_address,
-                       cancellable, &stream, &error);
-
-       g_object_unref (cia);
-
-       /* Ignore cancellations. */
-       if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-               g_clear_error (&error);
-       } else if (error != NULL) {
-               g_warning ("%s: %s", G_STRFUNC, error->message);
-               g_clear_error (&error);
-       }
-
-exit:
-       if (!stream)
-               stream = get_empty_image_stream ();
-
-       webkit_uri_scheme_request_finish (request, stream, -1, "image/*");
-
-       g_object_unref (request);
-       g_object_unref (stream);
-
-       if (uri_query)
-               g_hash_table_destroy (uri_query);
-
-       if (soup_uri)
-               soup_uri_free (soup_uri);
-
-       g_task_return_boolean (task, TRUE);
-}
-
-static void
-mail_display_mail_uri_scheme_appeared_cb (WebKitURISchemeRequest *request)
-{
-       EMailDisplay *display;
-       GTask *task;
-       GCancellable *cancellable;
-       const gchar *uri;
-
-       display = E_MAIL_DISPLAY (webkit_uri_scheme_request_get_web_view (request));
-
-       g_return_if_fail (E_IS_MAIL_DISPLAY (display));
-
-       cancellable = g_cancellable_new ();
-
-       uri = webkit_uri_scheme_request_get_uri (request);
-
-       task = g_task_new (
-               display, cancellable,
-               (GAsyncReadyCallback) mail_display_process_uri_scheme_finished_cb,
-               request);
-
-       g_task_set_task_data (task, g_object_ref (request), NULL);
-
-       if (g_ascii_strncasecmp (uri, "mail://contact-photo", 20) == 0)
-               g_task_run_in_thread (task, mail_display_process_contact_photo_uri_scheme_request);
-       else
-               g_task_run_in_thread (task, mail_display_process_mail_uri_scheme_request);
-
-       g_object_unref (task);
-       g_object_unref (cancellable);
-}
-
-static void
-mail_display_initialize_web_context (void)
-{
-       WebKitWebContext *web_context = webkit_web_context_get_default ();
-
-       webkit_web_context_register_uri_scheme (
-               web_context,
-               "evo-http",
-               (WebKitURISchemeRequestCallback) mail_display_http_uri_scheme_appeared_cb,
-               NULL,
-               NULL);
-
-       webkit_web_context_register_uri_scheme (
-               web_context,
-               "evo-https",
-               (WebKitURISchemeRequestCallback) mail_display_http_uri_scheme_appeared_cb,
-               NULL,
-               NULL);
-
-       webkit_web_context_register_uri_scheme (
-               web_context,
-               "mail",
-               (WebKitURISchemeRequestCallback) mail_display_mail_uri_scheme_appeared_cb,
-               NULL,
-               NULL);
-
-       webkit_web_context_register_uri_scheme (
-               web_context,
-               "cid",
-               (WebKitURISchemeRequestCallback) mail_display_cid_uri_scheme_appeared_cb,
-               NULL,
-               NULL);
-}
-
-static void
 e_mail_display_class_init (EMailDisplayClass *class)
 {
        GObjectClass *object_class;
@@ -2549,8 +1762,6 @@ e_mail_display_class_init (EMailDisplayClass *class)
 
        g_type_class_add_private (class, sizeof (EMailDisplayPrivate));
 
-       mail_display_initialize_web_context ();
-
        object_class = G_OBJECT_CLASS (class);
        object_class->constructed = mail_display_constructed;
        object_class->set_property = mail_display_set_property;
diff --git a/mail/e-mail-request.c b/mail/e-mail-request.c
index 49e175a..a75710d 100644
--- a/mail/e-mail-request.c
+++ b/mail/e-mail-request.c
@@ -15,19 +15,15 @@
  *
  */
 
-#define LIBSOUP_USE_UNSTABLE_REQUEST_API
-
-#include "e-mail-request.h"
-#include "em-utils.h"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
 
 #include <libsoup/soup.h>
-#include <libsoup/soup-requester.h>
-#include <libsoup/soup-request-http.h>
-
-#include <webkit2/webkit2.h>
 
 #include <glib/gi18n.h>
 #include <camel/camel.h>
+#include <libedataserver/libedataserver.h>
 
 #include "shell/e-shell.h"
 
@@ -35,82 +31,92 @@
 #include "em-format/e-mail-formatter-utils.h"
 #include "em-format/e-mail-formatter-print.h"
 
+#include "em-utils.h"
 #include "e-mail-ui-session.h"
+#include "e-mail-request.h"
 
 #define d(x)
-#define dd(x)
-
-#define E_MAIL_REQUEST_GET_PRIVATE(obj) \
-       (G_TYPE_INSTANCE_GET_PRIVATE \
-       ((obj), E_TYPE_MAIL_REQUEST, EMailRequestPrivate))
 
 struct _EMailRequestPrivate {
-       GBytes *bytes;
-       gchar *mime_type;
+       gint dummy;
+};
 
-       GHashTable *uri_query;
-       gchar *uri_base;
-       gchar *full_uri;
+static void e_mail_request_content_request_init (EContentRequestInterface *iface);
 
-       gboolean part_converted_to_utf8;
-       gchar *ret_mime_type;
-};
+G_DEFINE_TYPE_WITH_CODE (EMailRequest, e_mail_request, G_TYPE_OBJECT,
+       G_IMPLEMENT_INTERFACE (E_TYPE_CONTENT_REQUEST, e_mail_request_content_request_init))
 
-static const gchar *data_schemes[] = { "mail", NULL };
+static gboolean
+e_mail_request_can_process_uri (EContentRequest *request,
+                               const gchar *uri)
+{
+       g_return_val_if_fail (E_IS_MAIL_REQUEST (request), FALSE);
+       g_return_val_if_fail (uri != NULL, FALSE);
 
-G_DEFINE_TYPE (EMailRequest, e_mail_request, SOUP_TYPE_REQUEST)
+       return g_ascii_strncasecmp (uri, "mail:", 5) == 0;
+}
 
-static void
-handle_mail_request (GSimpleAsyncResult *simple,
-                     GObject *object,
-                     GCancellable *cancellable)
+static gboolean
+mail_request_process_mail_sync (EContentRequest *request,
+                               SoupURI *suri,
+                               GHashTable *uri_query,
+                               GObject *requester,
+                               GInputStream **out_stream,
+                               gint64 *out_stream_length,
+                               gchar **out_mime_type,
+                               GCancellable *cancellable,
+                               GError **error)
 {
-       EMailRequest *request = E_MAIL_REQUEST (object);
        EMailFormatter *formatter;
        EMailPartList *part_list;
        CamelObjectBag *registry;
-       GInputStream *input_stream;
        GOutputStream *output_stream;
+       GBytes *bytes;
+       gchar *tmp, *use_mime_type = NULL;
        const gchar *val;
        const gchar *default_charset, *charset;
+       gboolean part_converted_to_utf8 = FALSE;
 
        EMailFormatterContext context = { 0 };
 
-       if (g_cancellable_is_cancelled (cancellable))
-               return;
+       if (g_cancellable_set_error_if_cancelled (cancellable, error))
+               return FALSE;
+
+       tmp = g_strdup_printf ("%s://%s%s", suri->scheme, suri->host, suri->path);
 
        registry = e_mail_part_list_get_registry ();
-       part_list = camel_object_bag_get (registry, request->priv->uri_base);
+       part_list = camel_object_bag_get (registry, tmp);
+
+       g_free (tmp);
+
+       context.uri = soup_uri_to_string (suri, FALSE);
 
        if (camel_debug_start ("emformat:requests")) {
-               printf ("%s: found part-list %p for full_uri '%s'\n", G_STRFUNC, part_list, 
request->priv->full_uri);
+               printf ("%s: found part-list %p for full_uri '%s'\n", G_STRFUNC, part_list, context.uri);
                camel_debug_end ();
        }
 
-       if (!part_list)
-               return;
+       if (!part_list) {
+               g_free (context.uri);
+               return FALSE;
+       }
 
-       val = g_hash_table_lookup (
-               request->priv->uri_query, "headers_collapsed");
+       val = g_hash_table_lookup (uri_query, "headers_collapsed");
        if (val != NULL && atoi (val) == 1)
                context.flags |= E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED;
 
-       val = g_hash_table_lookup (
-               request->priv->uri_query, "headers_collapsable");
+       val = g_hash_table_lookup (uri_query, "headers_collapsable");
        if (val != NULL && atoi (val) == 1)
                context.flags |= E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSABLE;
 
-       val = g_hash_table_lookup (request->priv->uri_query, "mode");
+       val = g_hash_table_lookup (uri_query, "mode");
        if (val != NULL)
                context.mode = atoi (val);
 
-       default_charset = g_hash_table_lookup (
-               request->priv->uri_query, "formatter_default_charset");
-       charset = g_hash_table_lookup (
-               request->priv->uri_query, "formatter_charset");
+       default_charset = g_hash_table_lookup (uri_query, "formatter_default_charset");
+       charset = g_hash_table_lookup (uri_query, "formatter_charset");
 
        context.part_list = g_object_ref (part_list);
-       context.uri = request->priv->full_uri;
 
        if (context.mode == E_MAIL_FORMATTER_MODE_PRINTING)
                formatter = e_mail_formatter_print_new ();
@@ -124,7 +130,7 @@ handle_mail_request (GSimpleAsyncResult *simple,
 
        output_stream = g_memory_output_stream_new_resizable ();
 
-       val = g_hash_table_lookup (request->priv->uri_query, "part_id");
+       val = g_hash_table_lookup (uri_query, "part_id");
        if (val != NULL) {
                EMailPart *part;
                const gchar *mime_type;
@@ -143,8 +149,7 @@ handle_mail_request (GSimpleAsyncResult *simple,
                }
                g_free (part_id);
 
-               mime_type = g_hash_table_lookup (
-                       request->priv->uri_query, "mime_type");
+               mime_type = g_hash_table_lookup (uri_query, "mime_type");
 
                if (context.mode == E_MAIL_FORMATTER_MODE_SOURCE)
                        mime_type = "application/vnd.evolution.source";
@@ -155,11 +160,10 @@ handle_mail_request (GSimpleAsyncResult *simple,
 
                        mime_part = e_mail_part_ref_mime_part (part);
                        dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
-                       g_return_if_fail (dw);
+                       g_return_val_if_fail (dw != NULL, FALSE);
 
                        if (!mime_type) {
-                               g_free (request->priv->mime_type);
-                               request->priv->mime_type = camel_data_wrapper_get_mime_type (dw);
+                               use_mime_type = camel_data_wrapper_get_mime_type (dw);
                        }
 
                        camel_data_wrapper_decode_to_output_stream_sync (
@@ -175,7 +179,7 @@ handle_mail_request (GSimpleAsyncResult *simple,
                                output_stream, mime_type,
                                cancellable);
 
-                       request->priv->part_converted_to_utf8 = e_mail_part_get_converted_to_utf8 (part);
+                       part_converted_to_utf8 = e_mail_part_get_converted_to_utf8 (part);
                }
 
                g_object_unref (part);
@@ -191,61 +195,54 @@ handle_mail_request (GSimpleAsyncResult *simple,
 
        g_output_stream_close (output_stream, NULL, NULL);
 
-       if (request->priv->bytes != NULL)
-               g_bytes_unref (request->priv->bytes);
-
-       request->priv->bytes = g_memory_output_stream_steal_as_bytes (
-               G_MEMORY_OUTPUT_STREAM (output_stream));
+       bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (output_stream));
 
-       if (g_bytes_get_size (request->priv->bytes) == 0) {
+       if (g_bytes_get_size (bytes) == 0) {
                gchar *data;
 
-               g_bytes_unref (request->priv->bytes);
+               g_bytes_unref (bytes);
 
                data = g_strdup_printf (
                        "<p align='center'>%s</p>",
                        _("The message has no text content."));
 
                /* Takes ownership of the string. */
-               request->priv->bytes = g_bytes_new_take (
-                       data, strlen (data) + 1);
+               bytes = g_bytes_new_take (data, strlen (data) + 1);
        }
 
-       input_stream =
-               g_memory_input_stream_new_from_bytes (request->priv->bytes);
+       if (!use_mime_type)
+               use_mime_type = g_strdup ("text/html");
 
-       g_simple_async_result_set_op_res_gpointer (
-               simple, g_object_ref (input_stream),
-               (GDestroyNotify) g_object_unref);
+       if (part_converted_to_utf8 && g_strcmp0 (use_mime_type, "text/html") == 0) {
+               tmp = g_strconcat (use_mime_type, "; charset=\"UTF-8\"", NULL);
+               g_free (use_mime_type);
+               use_mime_type = tmp;
+       }
 
-       g_object_unref (input_stream);
-       g_object_unref (output_stream);
+       *out_stream = g_memory_input_stream_new_from_bytes (bytes);
+       *out_stream_length = g_bytes_get_size (bytes);
+       *out_mime_type = use_mime_type;
 
+       g_object_unref (output_stream);
        g_object_unref (part_list);
        g_object_unref (formatter);
-}
-
-static GInputStream *
-get_empty_image_stream (void)
-{
-       GdkPixbuf *pixbuf;
-       gchar *buffer;
-       gsize length;
+       g_bytes_unref (bytes);
+       g_free (context.uri);
 
-       pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
-       gdk_pixbuf_fill (pixbuf, 0x00000000); /* transparent black */
-       gdk_pixbuf_save_to_buffer (pixbuf, &buffer, &length, "png", NULL, NULL);
-       g_object_unref (pixbuf);
-
-       return g_memory_input_stream_new_from_data (buffer, length, g_free);
+       return TRUE;
 }
 
-static void
-handle_contact_photo_request (GSimpleAsyncResult *simple,
-                              GObject *object,
-                              GCancellable *cancellable)
+static gboolean
+mail_request_process_contact_photo_sync (EContentRequest *request,
+                                        SoupURI *suri,
+                                        GHashTable *uri_query,
+                                        GObject *requester,
+                                        GInputStream **out_stream,
+                                        gint64 *out_stream_length,
+                                        gchar **out_mime_type,
+                                        GCancellable *cancellable,
+                                        GError **error)
 {
-       EMailRequest *request = E_MAIL_REQUEST (object);
        EShell *shell;
        EShellBackend *shell_backend;
        EMailBackend *mail_backend;
@@ -256,227 +253,171 @@ handle_contact_photo_request (GSimpleAsyncResult *simple,
        const gchar *email_address;
        const gchar *escaped_string;
        gchar *unescaped_string;
-       GError *error = NULL;
+       gboolean success = FALSE;
 
-       /* XXX Is this really the only way to obtain
-        *     the mail session instance from here? */
        shell = e_shell_get_default ();
        shell_backend = e_shell_get_backend_by_name (shell, "mail");
        mail_backend = E_MAIL_BACKEND (shell_backend);
        mail_session = e_mail_backend_get_session (mail_backend);
 
-       photo_cache = e_mail_ui_session_get_photo_cache (
-               E_MAIL_UI_SESSION (mail_session));
-
-       request->priv->mime_type = g_strdup ("image/*");
-
-       escaped_string = g_hash_table_lookup (
-               request->priv->uri_query, "mailaddr");
-       if (escaped_string == NULL || *escaped_string == '\0')
-               goto exit;
+       photo_cache = e_mail_ui_session_get_photo_cache (E_MAIL_UI_SESSION (mail_session));
 
-       cia = camel_internet_address_new ();
+       escaped_string = g_hash_table_lookup (uri_query, "mailaddr");
+       if (escaped_string && *escaped_string) {
+               cia = camel_internet_address_new ();
 
-       unescaped_string = g_uri_unescape_string (escaped_string, NULL);
-       camel_address_decode (CAMEL_ADDRESS (cia), unescaped_string);
-       g_free (unescaped_string);
+               unescaped_string = g_uri_unescape_string (escaped_string, NULL);
+               camel_address_decode (CAMEL_ADDRESS (cia), unescaped_string);
+               g_free (unescaped_string);
 
-       if (camel_internet_address_get (cia, 0, NULL, &email_address))
-               e_photo_cache_get_photo_sync (
-                       photo_cache, email_address,
-                       cancellable, &stream, &error);
+               if (camel_internet_address_get (cia, 0, NULL, &email_address))
+                       success = e_photo_cache_get_photo_sync (
+                               photo_cache, email_address,
+                               cancellable, &stream, error);
 
-       g_object_unref (cia);
+               g_object_unref (cia);
 
-       /* Ignore cancellations. */
-       if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-               g_clear_error (&error);
-       } else if (error != NULL) {
-               g_warning ("%s: %s", G_STRFUNC, error->message);
-               g_clear_error (&error);
+               if (success) {
+                       *out_stream = stream;
+                       *out_stream_length = -1;
+                       *out_mime_type = g_strdup ("image/*");
+               }
        }
 
-exit:
-       if (stream == NULL)
-               stream = get_empty_image_stream ();
-
-       g_simple_async_result_set_op_res_gpointer (
-               simple, g_object_ref (stream),
-               (GDestroyNotify) g_object_unref);
-
-       g_object_unref (stream);
+       return success;
 }
 
-static void
-mail_request_finalize (GObject *object)
+typedef struct _MailIdleData
 {
-       EMailRequestPrivate *priv;
+       EContentRequest *request;
+       SoupURI *suri;
+       GHashTable *uri_query;
+       GObject *requester;
+       GInputStream **out_stream;
+       gint64 *out_stream_length;
+       gchar **out_mime_type;
+       GCancellable *cancellable;
+       GError **error;
+
+       gboolean success;
+       EFlag *flag;
+} MailIdleData;
 
-       priv = E_MAIL_REQUEST_GET_PRIVATE (object);
+static gboolean
+process_mail_request_idle_cb (gpointer user_data)
+{
+       MailIdleData *mid = user_data;
 
-       if (priv->bytes != NULL)
-               g_bytes_unref (priv->bytes);
+       g_return_val_if_fail (mid != NULL, FALSE);
+       g_return_val_if_fail (E_IS_MAIL_REQUEST (mid->request), FALSE);
+       g_return_val_if_fail (mid->suri != NULL, FALSE);
+       g_return_val_if_fail (mid->flag != NULL, FALSE);
 
-       if (priv->uri_query != NULL)
-               g_hash_table_destroy (priv->uri_query);
+       mid->success = mail_request_process_mail_sync (mid->request,
+               mid->suri, mid->uri_query, mid->requester, mid->out_stream,
+               mid->out_stream_length, mid->out_mime_type,
+               mid->cancellable, mid->error);
 
-       g_free (priv->mime_type);
-       g_free (priv->uri_base);
-       g_free (priv->full_uri);
-       g_free (priv->ret_mime_type);
+       e_flag_set (mid->flag);
 
-       /* Chain up to parent's finalize() method. */
-       G_OBJECT_CLASS (e_mail_request_parent_class)->finalize (object);
+       return FALSE;
 }
 
 static gboolean
-mail_request_check_uri (SoupRequest *request,
-                       SoupURI *uri,
-                       GError **error)
-{
-       return (strcmp (uri->scheme, "mail") == 0);
-}
-
-static void
-mail_request_send_async (SoupRequest *request,
-                         GCancellable *cancellable,
-                         GAsyncReadyCallback callback,
-                         gpointer user_data)
+e_mail_request_process_sync (EContentRequest *request,
+                            const gchar *uri,
+                            GObject *requester,
+                            GInputStream **out_stream,
+                            gint64 *out_stream_length,
+                            gchar **out_mime_type,
+                            GCancellable *cancellable,
+                            GError **error)
 {
-       EMailRequestPrivate *priv;
-       GSimpleAsyncResult *simple;
-       SoupURI *uri;
+       SoupURI *suri;
+       GHashTable *uri_query;
+       gboolean success = FALSE;
 
-       priv = E_MAIL_REQUEST_GET_PRIVATE (request);
+       g_return_val_if_fail (E_IS_MAIL_REQUEST (request), FALSE);
+       g_return_val_if_fail (uri != NULL, FALSE);
 
-       uri = soup_request_get_uri (request);
+       if (g_cancellable_set_error_if_cancelled (cancellable, error))
+               return FALSE;
 
-       d (printf ("received request for %s\n", soup_uri_to_string (uri, FALSE)));
+       suri = soup_uri_new (uri);
+       g_return_val_if_fail (suri != NULL, FALSE);
 
-       if (uri->query) {
-               priv->uri_query = soup_form_decode (uri->query);
+       if (suri->query) {
+               uri_query = soup_form_decode (suri->query);
        } else {
-               priv->uri_query = NULL;
+               uri_query = NULL;
        }
 
-       priv->full_uri = soup_uri_to_string (uri, FALSE);
-       priv->uri_base = g_strdup_printf (
-               "%s://%s%s", uri->scheme, uri->host, uri->path);
-
-       simple = g_simple_async_result_new (
-               G_OBJECT (request), callback,
-               user_data, mail_request_send_async);
-
-       g_simple_async_result_set_check_cancellable (simple, cancellable);
-
-       if (g_strcmp0 (uri->host, "contact-photo") == 0) {
-               e_util_run_simple_async_result_in_thread (
-                       simple, handle_contact_photo_request,
-                       cancellable);
+       if (g_strcmp0 (suri->host, "contact-photo") == 0) {
+               success = mail_request_process_contact_photo_sync (request, suri, uri_query, requester,
+                       out_stream, out_stream_length, out_mime_type, cancellable, error);
        } else {
-               /* Process e-mail mail requests in this thread, which should be
-                * the main/UI thread, because any EMailFormatter can create
-                * GtkWidget-s, or manipulate with them, which should be always
-                * done in the main/UI thread. */
-               handle_mail_request (simple, G_OBJECT (request), cancellable);
-               g_simple_async_result_complete_in_idle (simple);
-       }
-
-       g_object_unref (simple);
-}
-
-static GInputStream *
-mail_request_send_finish (SoupRequest *request,
-                          GAsyncResult *result,
-                          GError **error)
-{
-       GSimpleAsyncResult *simple;
-       GInputStream *stream;
-
-       simple = G_SIMPLE_ASYNC_RESULT (result);
-       stream = g_simple_async_result_get_op_res_gpointer (simple);
+               MailIdleData mid;
+
+               mid.request = request;
+               mid.suri = suri;
+               mid.uri_query = uri_query;
+               mid.requester = requester;
+               mid.out_stream = out_stream;
+               mid.out_stream_length = out_stream_length;
+               mid.out_mime_type = out_mime_type;
+               mid.cancellable = cancellable;
+               mid.error = error;
+               mid.flag = e_flag_new ();
+               mid.success = FALSE;
+
+               if (e_util_is_main_thread (NULL)) {
+                       process_mail_request_idle_cb (&mid);
+               } else {
+                       /* Process e-mail mail requests in this thread, which should be
+                        * the main/UI thread, because any EMailFormatter can create
+                        * GtkWidget-s, or manipulate with them, which should be always
+                        * done in the main/UI thread. */
+                       g_idle_add_full (
+                               G_PRIORITY_HIGH_IDLE,
+                               process_mail_request_idle_cb,
+                               &mid, NULL);
+
+                       e_flag_wait (mid.flag);
+               }
 
-       /* Reset the stream before passing it back to webkit */
-       if (G_IS_SEEKABLE (stream))
-               g_seekable_seek (
-                       G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL);
+               e_flag_free (mid.flag);
 
-       if (stream == NULL) {
-               /* We must always return something */
-               stream = g_memory_input_stream_new ();
-       } else {
-               g_object_ref (stream);
+               success = mid.success;
        }
 
-       return stream;
-}
+       if (uri_query)
+               g_hash_table_destroy (uri_query);
+       soup_uri_free (suri);
 
-static goffset
-mail_request_get_content_length (SoupRequest *request)
-{
-       EMailRequestPrivate *priv;
-       goffset content_length = -1;  /* -1 means unknown */
-
-       priv = E_MAIL_REQUEST_GET_PRIVATE (request);
-
-       if (priv->bytes != NULL)
-               content_length = g_bytes_get_size (priv->bytes);
-
-       return content_length;
+       return success;
 }
 
-static const gchar *
-mail_request_get_content_type (SoupRequest *request)
+static void
+e_mail_request_content_request_init (EContentRequestInterface *iface)
 {
-       EMailRequestPrivate *priv;
-       gchar *mime_type;
-
-       priv = E_MAIL_REQUEST_GET_PRIVATE (request);
-
-       if (priv->mime_type != NULL) {
-               mime_type = g_strdup (priv->mime_type);
-       } else {
-               mime_type = g_strdup ("text/html");
-       }
-
-       if (g_strcmp0 (mime_type, "text/html") == 0 &&
-           priv->part_converted_to_utf8) {
-               priv->ret_mime_type = g_strconcat (
-                       mime_type, "; charset=\"UTF-8\"", NULL);
-               g_free (mime_type);
-       } else {
-               priv->ret_mime_type = mime_type;
-       }
-
-       d (printf ("Content-Type: %s\n", priv->ret_mime_type));
-
-       return priv->ret_mime_type;
+       iface->can_process_uri = e_mail_request_can_process_uri;
+       iface->process_sync = e_mail_request_process_sync;
 }
 
 static void
 e_mail_request_class_init (EMailRequestClass *class)
 {
-       GObjectClass *object_class;
-       SoupRequestClass *request_class;
-
        g_type_class_add_private (class, sizeof (EMailRequestPrivate));
-
-       object_class = G_OBJECT_CLASS (class);
-       object_class->finalize = mail_request_finalize;
-
-       request_class = SOUP_REQUEST_CLASS (class);
-       request_class->schemes = data_schemes;
-       request_class->send_async = mail_request_send_async;
-       request_class->send_finish = mail_request_send_finish;
-       request_class->get_content_type = mail_request_get_content_type;
-       request_class->get_content_length = mail_request_get_content_length;
-       request_class->check_uri = mail_request_check_uri;
 }
 
 static void
 e_mail_request_init (EMailRequest *request)
 {
-       request->priv = E_MAIL_REQUEST_GET_PRIVATE (request);
-       request->priv->part_converted_to_utf8 = FALSE;
+       request->priv = G_TYPE_INSTANCE_GET_PRIVATE (request, E_TYPE_MAIL_REQUEST, EMailRequestPrivate);
 }
 
+EContentRequest *
+e_mail_request_new (void)
+{
+       return g_object_new (E_TYPE_MAIL_REQUEST, NULL);
+}
diff --git a/mail/e-mail-request.h b/mail/e-mail-request.h
index c85266e..cd35992 100644
--- a/mail/e-mail-request.h
+++ b/mail/e-mail-request.h
@@ -18,10 +18,7 @@
 #ifndef E_MAIL_REQUEST_H
 #define E_MAIL_REQUEST_H
 
-#define LIBSOUP_USE_UNSTABLE_REQUEST_API
-
-#include <libsoup/soup.h>
-#include <libsoup/soup-request.h>
+#include <e-util/e-util.h>
 
 /* Standard GObject macros */
 #define E_TYPE_MAIL_REQUEST \
@@ -49,15 +46,17 @@ typedef struct _EMailRequestClass EMailRequestClass;
 typedef struct _EMailRequestPrivate EMailRequestPrivate;
 
 struct _EMailRequest {
-       SoupRequest parent;
+       GObject parent;
        EMailRequestPrivate *priv;
 };
 
 struct _EMailRequestClass {
-       SoupRequestClass parent;
+       GObjectClass parent;
 };
 
 GType          e_mail_request_get_type         (void) G_GNUC_CONST;
+EContentRequest *
+               e_mail_request_new              (void);
 
 G_END_DECLS
 
diff --git a/shell/main.c b/shell/main.c
index 8b898b5..6788ac2 100644
--- a/shell/main.c
+++ b/shell/main.c
@@ -569,6 +569,7 @@ main (gint argc,
                handle_term_signal, NULL, NULL);
 #endif
 
+       e_util_init_main_thread (NULL);
        e_passwords_init ();
 
        gtk_window_set_default_icon_name ("evolution");


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]