[libsoup/wip/http2-upstreaming: 1/2] Turn soup-message-io into an interface




commit a61d6a9d3fad6795c5fb3cd990328817dce96fb8
Author: Patrick Griffis <pgriffis igalia com>
Date:   Fri Nov 20 14:45:26 2020 -0600

    Turn soup-message-io into an interface
    
    This allows abstracting over http1 and http2

 docs/reference/meson.build                         |   1 +
 libsoup/meson.build                                |   3 +-
 libsoup/server/soup-server-io.c                    |   1 +
 libsoup/soup-connection.c                          |   6 +-
 libsoup/soup-logger-private.h                      |   2 +-
 libsoup/soup-logger.c                              |   9 +-
 libsoup/soup-message-io-backend.c                  | 168 +++++++++++
 libsoup/soup-message-io-backend.h                  | 100 +++++++
 libsoup/soup-message-io-data.c                     |   2 +-
 libsoup/soup-message-io-data.h                     |  11 +-
 .../{soup-message-io.c => soup-message-io-http1.c} | 320 +++++++++++----------
 libsoup/soup-message-io-http1.h                    |  33 +++
 libsoup/soup-message-private.h                     |  54 +---
 libsoup/soup-message.c                             |  68 ++++-
 14 files changed, 545 insertions(+), 233 deletions(-)
---
diff --git a/docs/reference/meson.build b/docs/reference/meson.build
index de67bb20..c8ce6e59 100644
--- a/docs/reference/meson.build
+++ b/docs/reference/meson.build
@@ -34,6 +34,7 @@ ignore_headers = [
   'soup-private-enum-types.h',
   'soup-server-message-private.h',
   'soup-message-io-data.h',
+  'soup-message-io-http1.h',
   'soup-uri-utils-private.h',
   'soup-session-feature-private.h',
   'soup-message-metrics-private.h',
diff --git a/libsoup/meson.build b/libsoup/meson.build
index adcccc3e..629962b3 100644
--- a/libsoup/meson.build
+++ b/libsoup/meson.build
@@ -62,7 +62,8 @@ soup_sources = [
   'soup-logger-input-stream.c',
   'soup-message.c',
   'soup-message-headers.c',
-  'soup-message-io.c',
+  'soup-message-io-backend.c',
+  'soup-message-io-http1.c',
   'soup-message-io-data.c',
   'soup-message-metrics.c',
   'soup-message-queue-item.c',
diff --git a/libsoup/server/soup-server-io.c b/libsoup/server/soup-server-io.c
index a806d2f3..45c22bf8 100644
--- a/libsoup/server/soup-server-io.c
+++ b/libsoup/server/soup-server-io.c
@@ -15,6 +15,7 @@
 #include "soup-body-input-stream.h"
 #include "soup-body-output-stream.h"
 #include "soup-filter-input-stream.h"
+#include "soup-message-io-backend.h"
 #include "soup-server-message-private.h"
 #include "soup-misc.h"
 #include "soup-socket.h"
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index 4beb599b..71f0dcf9 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -13,6 +13,7 @@
 #include "soup.h"
 #include "soup-io-stream.h"
 #include "soup-message-queue-item.h"
+#include "soup-message-io-http1.h"
 #include "soup-socket-properties.h"
 #include "soup-private-enum-types.h"
 #include <gio/gnetworking.h>
@@ -1067,7 +1068,10 @@ soup_connection_send_request (SoupConnection           *conn,
        else
                priv->reusable = FALSE;
 
-       soup_message_send_request (item, completion_cb, user_data);
+        SoupMessageIOHTTP1 *http1 = soup_message_io_http1_new ();
+        soup_message_set_io_data (item->msg, SOUP_MESSAGE_IO_BACKEND (http1));
+        soup_message_io_backend_send_item (SOUP_MESSAGE_IO_BACKEND (http1),
+                                           item, completion_cb, user_data);
 }
 
 GTlsCertificate *
diff --git a/libsoup/soup-logger-private.h b/libsoup/soup-logger-private.h
index 8307319a..23de245c 100644
--- a/libsoup/soup-logger-private.h
+++ b/libsoup/soup-logger-private.h
@@ -9,6 +9,6 @@
 
 G_BEGIN_DECLS
 
-void soup_logger_request_body_setup (SoupLogger *logger, SoupMessage *msg);
+void soup_logger_request_body_setup (SoupLogger *logger, SoupMessage *msg, SoupBodyOutputStream *stream);
 
 G_END_DECLS
diff --git a/libsoup/soup-logger.c b/libsoup/soup-logger.c
index c9899e22..39cee2a1 100644
--- a/libsoup/soup-logger.c
+++ b/libsoup/soup-logger.c
@@ -841,16 +841,15 @@ body_ostream_done (gpointer data, GObject *bostream)
 }
 
 void
-soup_logger_request_body_setup (SoupLogger *logger, SoupMessage *msg)
+soup_logger_request_body_setup (SoupLogger *logger, SoupMessage *msg, SoupBodyOutputStream *stream)
 {
         SoupLoggerPrivate *priv = soup_logger_get_instance_private (logger);
-        SoupMessageIOData *io = (SoupMessageIOData *)soup_message_get_io_data (msg);
 
-        g_hash_table_insert (priv->request_messages, io->body_ostream, msg);
-        g_signal_connect_object (io->body_ostream, "wrote-data",
+        g_hash_table_insert (priv->request_messages, stream, msg);
+        g_signal_connect_object (stream, "wrote-data",
                                  G_CALLBACK (body_stream_wrote_data_cb),
                                  logger, 0);
-        g_object_weak_ref (G_OBJECT (io->body_ostream), body_ostream_done, priv);
+        g_object_weak_ref (G_OBJECT (stream), body_ostream_done, priv);
 }
 
 static void
diff --git a/libsoup/soup-message-io-backend.c b/libsoup/soup-message-io-backend.c
new file mode 100644
index 00000000..cdabd224
--- /dev/null
+++ b/libsoup/soup-message-io-backend.c
@@ -0,0 +1,168 @@
+/* soup-message-io-backend.c
+ *
+ * Copyright 2020 Igalia S.L.
+ *
+ * This file 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; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ */
+
+#include "config.h"
+
+#include "soup-message-io-backend.h"
+#include "soup-message-private.h"
+
+G_DEFINE_INTERFACE (SoupMessageIOBackend, soup_message_io_backend, G_TYPE_OBJECT)
+
+void
+soup_message_io_run (SoupMessage *msg,
+                     gboolean     blocking)
+{
+        SoupMessageIOBackend *backend = soup_message_get_io_data (msg);
+        if (backend) {
+                SoupMessageIOBackendInterface *iface = SOUP_MESSAGE_IO_BACKEND_GET_IFACE (backend);
+                iface->run (msg, blocking);
+        }
+}
+
+void
+soup_message_io_finished (SoupMessage *msg)
+{
+        SoupMessageIOBackend *backend = soup_message_get_io_data (msg);
+        if (backend) {
+                SoupMessageIOBackendInterface *iface = SOUP_MESSAGE_IO_BACKEND_GET_IFACE (backend);
+                iface->finished (msg);
+        }
+}
+
+void
+soup_message_io_pause (SoupMessage *msg)
+{
+        SoupMessageIOBackend *backend = soup_message_get_io_data (msg);
+        if (backend) {
+                SoupMessageIOBackendInterface *iface = SOUP_MESSAGE_IO_BACKEND_GET_IFACE (backend);
+                iface->pause (msg);
+        }
+}
+
+void
+soup_message_io_unpause (SoupMessage *msg)
+{
+        SoupMessageIOBackend *backend = soup_message_get_io_data (msg);
+        if (backend) {
+                SoupMessageIOBackendInterface *iface = SOUP_MESSAGE_IO_BACKEND_GET_IFACE (backend);
+                iface->unpause (msg);
+        }
+}
+
+void
+soup_message_io_stolen (SoupMessage *msg)
+{
+        SoupMessageIOBackend *backend = soup_message_get_io_data (msg);
+        if (backend) {
+                SoupMessageIOBackendInterface *iface = SOUP_MESSAGE_IO_BACKEND_GET_IFACE (backend);
+                iface->stolen (msg);
+        }
+}
+
+gboolean
+soup_message_io_in_progress (SoupMessage *msg)
+{
+        SoupMessageIOBackend *backend = soup_message_get_io_data (msg);
+        if (backend) {
+                SoupMessageIOBackendInterface *iface = SOUP_MESSAGE_IO_BACKEND_GET_IFACE (backend);
+                return iface->in_progress (msg);
+        }
+        return FALSE;
+}
+
+gboolean
+soup_message_io_is_paused (SoupMessage *msg)
+{
+        SoupMessageIOBackend *backend = soup_message_get_io_data (msg);
+        if (backend) {
+                SoupMessageIOBackendInterface *iface = SOUP_MESSAGE_IO_BACKEND_GET_IFACE (backend);
+                return iface->is_paused (msg);
+        }
+        return FALSE;
+}
+
+GInputStream *
+soup_message_io_get_response_istream (SoupMessage *msg,
+                                      GError **error)
+{
+        SoupMessageIOBackend *backend = soup_message_get_io_data (msg);
+        SoupMessageIOBackendInterface *iface = SOUP_MESSAGE_IO_BACKEND_GET_IFACE (backend);
+        return iface->get_response_istream (msg, error);
+}
+
+gboolean
+soup_message_io_run_until_read (SoupMessage *msg,
+                                GCancellable *cancellable,
+                                GError **error)
+{
+        SoupMessageIOBackend *backend = soup_message_get_io_data (msg);
+        SoupMessageIOBackendInterface *iface = SOUP_MESSAGE_IO_BACKEND_GET_IFACE (backend);
+        return iface->run_until_read (msg, cancellable, error);
+}
+
+gboolean
+soup_message_io_run_until_finish (SoupMessage *msg,
+                                  gboolean blocking,
+                                  GCancellable *cancellable,
+                                  GError **error)
+{
+        SoupMessageIOBackend *backend = soup_message_get_io_data (msg);
+        SoupMessageIOBackendInterface *iface = SOUP_MESSAGE_IO_BACKEND_GET_IFACE (backend);
+        return iface->run_until_finish (msg, blocking, cancellable, error);
+}
+
+void
+soup_message_io_run_until_read_async (SoupMessage        *msg,
+                                      int                 io_priority,
+                                      GCancellable       *cancellable,
+                                      GAsyncReadyCallback callback,
+                                      gpointer            user_data)
+{
+        SoupMessageIOBackend *backend = soup_message_get_io_data (msg);
+        SoupMessageIOBackendInterface *iface = SOUP_MESSAGE_IO_BACKEND_GET_IFACE (backend);
+        iface->run_until_read_async (msg, io_priority, cancellable, callback, user_data);
+}
+
+gboolean
+soup_message_io_run_until_read_finish (SoupMessage        *msg,
+                                       GAsyncResult       *result,
+                                       GError            **error)
+{
+        /* For now just assume all implemenations use GTask the same way as
+           it simplifies the lifecycle of the backend being destroyed before the
+           task returns */
+        return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+void
+soup_message_io_backend_send_item (SoupMessageIOBackend      *backend,
+                                   SoupMessageQueueItem      *item,
+                                   SoupMessageIOCompletionFn  completion_cb,
+                                   gpointer                   user_data)
+{
+        SoupMessageIOBackendInterface *iface = SOUP_MESSAGE_IO_BACKEND_GET_IFACE (backend);
+        iface->send_item (backend, item, completion_cb, user_data);
+}
+
+
+static void
+soup_message_io_backend_default_init (SoupMessageIOBackendInterface *iface)
+{
+}
\ No newline at end of file
diff --git a/libsoup/soup-message-io-backend.h b/libsoup/soup-message-io-backend.h
new file mode 100644
index 00000000..a43dc5bd
--- /dev/null
+++ b/libsoup/soup-message-io-backend.h
@@ -0,0 +1,100 @@
+/* soup-message-io-backend.h
+ *
+ * Copyright 2020 Igalia S.L.
+ *
+ * This file 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; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ */
+
+#pragma once
+
+#include "soup-types.h"
+#include "soup-message-headers.h"
+#include "soup-filter-input-stream.h"
+
+G_BEGIN_DECLS
+
+#define SOUP_TYPE_MESSAGE_IO_BACKEND (soup_message_io_backend_get_type ())
+
+G_DECLARE_INTERFACE (SoupMessageIOBackend, soup_message_io_backend, SOUP, MESSAGE_IO_BACKEND, GObject)
+
+typedef gboolean (*SoupMessageSourceFunc) (SoupMessage *, gpointer);
+
+typedef enum {
+       SOUP_MESSAGE_IO_COMPLETE,
+        SOUP_MESSAGE_IO_INTERRUPTED,
+        SOUP_MESSAGE_IO_STOLEN
+} SoupMessageIOCompletion;
+
+typedef void (*SoupMessageIOCompletionFn) (GObject                *msg,
+                                          SoupMessageIOCompletion completion,
+                                          gpointer                user_data);
+
+struct _SoupMessageIOBackendInterface
+{
+        GTypeInterface parent;
+
+        void (*finished) (SoupMessage *);
+        void (*cleanup) (SoupMessage *);
+        void (*pause) (SoupMessage *);
+        void (*unpause) (SoupMessage *);
+        void (*stolen) (SoupMessage *);
+        gboolean (*is_paused) (SoupMessage *);
+        gboolean (*in_progress) (SoupMessage *);
+        GSource * (*get_source) (SoupMessage *, GCancellable *, SoupMessageSourceFunc, gpointer);
+        GInputStream * (*get_response_istream) (SoupMessage *, GError **);
+        void (*run) (SoupMessage *, gboolean);
+        gboolean (*run_until_read) (SoupMessage *, GCancellable *, GError **);
+        gboolean (*run_until_finish) (SoupMessage *, gboolean, GCancellable *, GError **);
+        void (*run_until_read_async) (SoupMessage *, int, GCancellable *, GAsyncReadyCallback, gpointer);
+        void (*send_item) (SoupMessageIOBackend *, SoupMessageQueueItem *, SoupMessageIOCompletionFn, 
gpointer);
+};
+
+void       soup_message_io_finished    (SoupMessage *msg);
+void       soup_message_io_pause       (SoupMessage *msg);
+void       soup_message_io_unpause     (SoupMessage *msg);
+void       soup_message_io_stolen      (SoupMessage *msg);
+gboolean   soup_message_io_in_progress (SoupMessage *msg);
+gboolean   soup_message_io_is_paused   (SoupMessage *msg);
+
+void       soup_message_io_run         (SoupMessage *msg,
+                                       gboolean     blocking);
+
+gboolean soup_message_io_run_until_read        (SoupMessage        *msg,
+                                                GCancellable       *cancellable,
+                                                GError            **error);
+void     soup_message_io_run_until_read_async  (SoupMessage        *msg,
+                                               int                 io_priority,
+                                                GCancellable       *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer            user_data);
+gboolean soup_message_io_run_until_read_finish (SoupMessage        *msg,
+                                                GAsyncResult       *result,
+                                                GError            **error);
+
+gboolean soup_message_io_run_until_finish      (SoupMessage        *msg,
+                                                gboolean            blocking,
+                                                GCancellable       *cancellable,
+                                                GError            **error);
+
+GInputStream *soup_message_io_get_response_istream (SoupMessage  *msg,
+                                                   GError      **error);
+
+void soup_message_io_backend_send_item (SoupMessageIOBackend      *backend,
+                                        SoupMessageQueueItem      *item,
+                                        SoupMessageIOCompletionFn  completion_cb,
+                                        gpointer                   user_data);
+
+G_END_DECLS
\ No newline at end of file
diff --git a/libsoup/soup-message-io-data.c b/libsoup/soup-message-io-data.c
index 04a9c255..87026633 100644
--- a/libsoup/soup-message-io-data.c
+++ b/libsoup/soup-message-io-data.c
@@ -116,7 +116,7 @@ static gboolean
 message_io_is_paused (GObject *msg)
 {
        if (SOUP_IS_MESSAGE (msg))
-               return soup_message_is_io_paused (SOUP_MESSAGE (msg));
+               return soup_message_io_is_paused (SOUP_MESSAGE (msg));
 
        if (SOUP_IS_SERVER_MESSAGE (msg))
                return soup_server_message_is_io_paused (SOUP_SERVER_MESSAGE (msg));
diff --git a/libsoup/soup-message-io-data.h b/libsoup/soup-message-io-data.h
index e3feae7a..0f317385 100644
--- a/libsoup/soup-message-io-data.h
+++ b/libsoup/soup-message-io-data.h
@@ -8,6 +8,7 @@
 
 #include "soup-filter-input-stream.h"
 #include "soup-message-headers.h"
+#include "soup-message-io-backend.h"
 
 typedef enum {
        SOUP_MESSAGE_IO_STATE_NOT_STARTED,
@@ -31,16 +32,6 @@ typedef enum {
        (SOUP_MESSAGE_IO_STATE_ACTIVE (state) && \
         state != SOUP_MESSAGE_IO_STATE_BODY_DONE)
 
-typedef enum {
-       SOUP_MESSAGE_IO_COMPLETE,
-        SOUP_MESSAGE_IO_INTERRUPTED,
-        SOUP_MESSAGE_IO_STOLEN
-} SoupMessageIOCompletion;
-
-typedef void (*SoupMessageIOCompletionFn) (GObject                *msg,
-                                          SoupMessageIOCompletion completion,
-                                          gpointer                user_data);
-
 typedef struct {
        GIOStream              *iostream;
        SoupFilterInputStream  *istream;
diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io-http1.c
similarity index 82%
rename from libsoup/soup-message-io.c
rename to libsoup/soup-message-io-http1.c
index 68b437e5..cc43bbf6 100644
--- a/libsoup/soup-message-io.c
+++ b/libsoup/soup-message-io-http1.c
@@ -3,6 +3,22 @@
  * soup-message-io.c: HTTP message I/O
  *
  * Copyright (C) 2000-2003, Ximian, Inc.
+ * Copyright 2020 Igalia S.L.
+ *
+ * This file 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; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
  */
 
 #ifdef HAVE_CONFIG_H
@@ -15,6 +31,8 @@
 #include <sysprof-capture.h>
 #endif
 
+#include "soup-message-io-http1.h"
+
 #include "soup.h"
 #include "soup-body-input-stream.h"
 #include "soup-body-output-stream.h"
@@ -30,8 +48,9 @@
 #include "soup-misc.h"
 #include "soup-uri-utils-private.h"
 
-struct _SoupClientMessageIOData {
-       SoupMessageIOData base;
+struct _SoupMessageIOHTTP1 {
+       GObject parent_instance;
+        SoupMessageIOData base;
 
         SoupMessageQueueItem *item;
 
@@ -42,23 +61,16 @@ struct _SoupClientMessageIOData {
 #endif
 };
 
-#define RESPONSE_BLOCK_SIZE 8192
-#define HEADER_SIZE_LIMIT (64 * 1024)
-
-void
-soup_client_message_io_data_free (SoupClientMessageIOData *io)
-{
-       if (!io)
-               return;
+static void soup_message_io_http1_iface_init (SoupMessageIOBackendInterface *);
 
-       soup_message_io_data_cleanup (&io->base);
-       soup_message_queue_item_unref (io->item);
+G_DEFINE_TYPE_WITH_CODE (SoupMessageIOHTTP1, soup_message_io_http1, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (SOUP_TYPE_MESSAGE_IO_BACKEND, 
soup_message_io_http1_iface_init))
 
-       g_slice_free (SoupClientMessageIOData, io);
-}
+#define RESPONSE_BLOCK_SIZE 8192
+#define HEADER_SIZE_LIMIT (64 * 1024)
 
 static int
-soup_client_message_io_data_get_priority (SoupClientMessageIOData *io)
+soup_client_message_io_data_get_priority (SoupMessageIOHTTP1 *io)
 {
        if (!io->item->task)
                return G_PRIORITY_DEFAULT;
@@ -66,15 +78,21 @@ soup_client_message_io_data_get_priority (SoupClientMessageIOData *io)
        return g_task_get_priority (io->item->task);
 }
 
-void
-soup_message_io_finished (SoupMessage *msg)
+static SoupMessageIOHTTP1 *
+get_io_data (SoupMessage *msg)
 {
-       SoupClientMessageIOData *io;
+        return SOUP_MESSAGE_IO_HTTP1 (soup_message_get_io_data (msg));
+}
+
+static void
+soup_message_io_http1_finished (SoupMessage *msg)
+{
+       SoupMessageIOHTTP1 *io;
        SoupMessageIOCompletionFn completion_cb;
        gpointer completion_data;
        SoupMessageIOCompletion completion;
 
-       io = soup_message_get_io_data (msg);
+       io = get_io_data (msg);
        if (!io)
                return;
 
@@ -88,89 +106,36 @@ soup_message_io_finished (SoupMessage *msg)
                completion = SOUP_MESSAGE_IO_INTERRUPTED;
 
        g_object_ref (msg);
-       soup_message_set_io_data (msg, NULL);
+        soup_message_clear_io_data (msg);
        if (completion_cb)
                completion_cb (G_OBJECT (msg), completion, completion_data);
        g_object_unref (msg);
 }
 
-void
-soup_message_io_stolen (SoupMessage *msg)
+static void
+soup_message_io_http1_stolen (SoupMessage *msg)
 {
-       SoupClientMessageIOData *io;
+       SoupMessageIOHTTP1 *io = get_io_data (msg);
        SoupMessageIOCompletionFn completion_cb;
        gpointer completion_data;
 
-       io = soup_message_get_io_data (msg);
-       if (!io)
-               return;
-
        completion_cb = io->base.completion_cb;
        completion_data = io->base.completion_data;
 
        g_object_ref (msg);
-       soup_message_set_io_data (msg, NULL);
+        soup_message_clear_io_data (msg);
        if (completion_cb)
                completion_cb (G_OBJECT (msg), SOUP_MESSAGE_IO_STOLEN, completion_data);
        g_object_unref (msg);
 }
 
-static gint
-processing_stage_cmp (gconstpointer a,
-                      gconstpointer b)
-{
-       SoupProcessingStage stage_a = soup_content_processor_get_processing_stage (SOUP_CONTENT_PROCESSOR 
((gpointer)a));
-       SoupProcessingStage stage_b = soup_content_processor_get_processing_stage (SOUP_CONTENT_PROCESSOR 
((gpointer)b));
-
-       if (stage_a > stage_b)
-               return 1;
-       if (stage_a == stage_b)
-               return 0;
-       return -1;
-}
-
-GInputStream *
-soup_message_setup_body_istream (GInputStream *body_stream,
-                                SoupMessage *msg,
-                                SoupSession *session,
-                                SoupProcessingStage start_at_stage)
-{
-       GInputStream *istream;
-       GSList *p, *processors;
-
-       istream = g_object_ref (body_stream);
-
-       processors = soup_session_get_features (session, SOUP_TYPE_CONTENT_PROCESSOR);
-       processors = g_slist_sort (processors, processing_stage_cmp);
-
-       for (p = processors; p; p = p->next) {
-               GInputStream *wrapper;
-               SoupContentProcessor *processor;
-
-               processor = SOUP_CONTENT_PROCESSOR (p->data);
-               if (soup_message_disables_feature (msg, p->data) ||
-                   soup_content_processor_get_processing_stage (processor) < start_at_stage)
-                       continue;
-
-               wrapper = soup_content_processor_wrap_input (processor, istream, msg, NULL);
-               if (wrapper) {
-                       g_object_unref (istream);
-                       istream = wrapper;
-               }
-       }
-
-       g_slist_free (processors);
-
-       return istream;
-}
-
 static void
 request_body_stream_wrote_data_cb (SoupMessage *msg,
                                    const void  *buffer,
                                    guint        count,
                                    gboolean     is_metadata)
 {
-        SoupClientMessageIOData *client_io = soup_message_get_io_data (msg);
+        SoupMessageIOHTTP1 *client_io = get_io_data (msg);
 
         if (client_io->metrics) {
                 client_io->metrics->request_body_bytes_sent += count;
@@ -187,14 +152,14 @@ request_body_stream_wrote_cb (GOutputStream *ostream,
                              GAsyncResult  *result,
                              SoupMessage   *msg)
 {
-       SoupClientMessageIOData *io;
+       SoupMessageIOHTTP1 *io;
        gssize nwrote;
        GCancellable *async_wait;
        GError *error = NULL;
 
        nwrote = g_output_stream_splice_finish (ostream, result, &error);
 
-       io = soup_message_get_io_data (msg);
+       io = get_io_data (msg);
        if (!io || !io->base.async_wait || io->base.body_ostream != ostream) {
                g_clear_error (&error);
                g_object_unref (msg);
@@ -221,10 +186,10 @@ closed_async (GObject      *source,
 {
        GOutputStream *body_ostream = G_OUTPUT_STREAM (source);
        SoupMessage *msg = user_data;
-       SoupClientMessageIOData *io;
+       SoupMessageIOHTTP1 *io;
        GCancellable *async_wait;
 
-       io = soup_message_get_io_data (msg);
+       io = get_io_data (msg);
        if (!io || !io->base.async_wait || io->base.body_ostream != body_ostream) {
                g_object_unref (msg);
                return;
@@ -328,9 +293,9 @@ static gboolean
 io_write (SoupMessage *msg, gboolean blocking,
          GCancellable *cancellable, GError **error)
 {
-       SoupClientMessageIOData *client_io = soup_message_get_io_data (msg);
+       SoupMessageIOHTTP1 *client_io = get_io_data (msg);
        SoupMessageIOData *io = &client_io->base;
-       SoupSessionFeature *logger;
+        SoupSessionFeature *logger;
        gssize nwrote;
 
        if (io->async_error) {
@@ -386,7 +351,8 @@ io_write (SoupMessage *msg, gboolean blocking,
                logger = soup_session_get_feature_for_message (client_io->item->session,
                                                               SOUP_TYPE_LOGGER, msg);
                if (logger)
-                       soup_logger_request_body_setup (SOUP_LOGGER (logger), msg);
+                       soup_logger_request_body_setup (SOUP_LOGGER (logger), msg,
+                                                        SOUP_BODY_OUTPUT_STREAM (io->body_ostream));
                break;
 
        case SOUP_MESSAGE_IO_STATE_BODY:
@@ -516,7 +482,7 @@ static void
 response_network_stream_read_data_cb (SoupMessage *msg,
                                       guint        count)
 {
-        SoupClientMessageIOData *client_io = soup_message_get_io_data (msg);
+        SoupMessageIOHTTP1 *client_io = get_io_data (msg);
 
         if (client_io->base.read_state < SOUP_MESSAGE_IO_STATE_BODY_START)
                 client_io->metrics->response_header_bytes_received += count;
@@ -534,7 +500,7 @@ static gboolean
 io_read (SoupMessage *msg, gboolean blocking,
         GCancellable *cancellable, GError **error)
 {
-       SoupClientMessageIOData *client_io = soup_message_get_io_data (msg);
+       SoupMessageIOHTTP1 *client_io = get_io_data (msg);
        SoupMessageIOData *io = &client_io->base;
        gboolean succeeded;
         gboolean is_first_read;
@@ -605,7 +571,7 @@ io_read (SoupMessage *msg, gboolean blocking,
                        /* If this was "101 Switching Protocols", then
                         * the session may have stolen the connection...
                         */
-                       if (client_io != soup_message_get_io_data (msg))
+                       if (client_io != get_io_data (msg))
                                return FALSE;
 
                        soup_message_cleanup_response (msg);
@@ -707,7 +673,7 @@ io_read (SoupMessage *msg, gboolean blocking,
 static gboolean
 request_is_restartable (SoupMessage *msg, GError *error)
 {
-       SoupClientMessageIOData *client_io = soup_message_get_io_data (msg);
+       SoupMessageIOHTTP1 *client_io = get_io_data (msg);
        SoupMessageIOData *io = &client_io->base;
 
        if (!client_io)
@@ -728,7 +694,7 @@ io_run_until (SoupMessage *msg, gboolean blocking,
              SoupMessageIOState read_state, SoupMessageIOState write_state,
              GCancellable *cancellable, GError **error)
 {
-       SoupClientMessageIOData *client_io = soup_message_get_io_data (msg);
+       SoupMessageIOHTTP1 *client_io = get_io_data (msg);
        SoupMessageIOData *io = &client_io->base;
        gboolean progress = TRUE, done;
        GError *my_error = NULL;
@@ -744,7 +710,7 @@ io_run_until (SoupMessage *msg, gboolean blocking,
 
        g_object_ref (msg);
 
-       while (progress && soup_message_get_io_data (msg) == client_io && !io->paused && !io->async_wait &&
+       while (progress && get_io_data (msg) == client_io && !io->paused && !io->async_wait &&
               (io->read_state < read_state || io->write_state < write_state)) {
 
                if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->read_state))
@@ -759,7 +725,7 @@ io_run_until (SoupMessage *msg, gboolean blocking,
                g_propagate_error (error, my_error);
                g_object_unref (msg);
                return FALSE;
-       } else if (soup_message_get_io_data (msg) != client_io) {
+       } else if (get_io_data (msg) != client_io) {
                g_set_error_literal (error, G_IO_ERROR,
                                     G_IO_ERROR_CANCELLED,
                                     _("Operation was cancelled"));
@@ -814,11 +780,11 @@ io_run_until (SoupMessage *msg, gboolean blocking,
 }
 
 static void
-soup_message_io_finish (SoupMessage  *msg,
+soup_message_io_http1_finish (SoupMessage  *msg,
                        GError       *error)
 {
        if (request_is_restartable (msg, error)) {
-               SoupClientMessageIOData *io = soup_message_get_io_data (msg);
+               SoupMessageIOHTTP1 *io = get_io_data (msg);
 
                /* Connection got closed, but we can safely try again. */
                io->item->state = SOUP_MESSAGE_RESTARTING;
@@ -826,21 +792,25 @@ soup_message_io_finish (SoupMessage  *msg,
                 soup_message_set_metrics_timestamp (msg, SOUP_MESSAGE_METRICS_RESPONSE_END);
         }
 
-       soup_message_io_finished (msg);
+       soup_message_io_http1_finished (msg);
 }
 
+static void
+soup_message_io_http1_run (SoupMessage *msg,
+                          gboolean     blocking);
+
 static gboolean
 io_run_ready (SoupMessage *msg, gpointer user_data)
 {
-       soup_message_io_run (msg, FALSE);
+       soup_message_io_http1_run (msg, FALSE);
        return FALSE;
 }
 
-void
-soup_message_io_run (SoupMessage *msg,
-                    gboolean     blocking)
+static void
+soup_message_io_http1_run (SoupMessage *msg,
+                          gboolean     blocking)
 {
-       SoupClientMessageIOData *client_io = soup_message_get_io_data (msg);
+       SoupMessageIOHTTP1 *client_io = get_io_data (msg);
        SoupMessageIOData *io = &client_io->base;
        GError *error = NULL;
 
@@ -856,7 +826,7 @@ soup_message_io_run (SoupMessage *msg,
                          SOUP_MESSAGE_IO_STATE_DONE,
                          SOUP_MESSAGE_IO_STATE_DONE,
                          client_io->item->cancellable, &error)) {
-               soup_message_io_finished (msg);
+               soup_message_io_http1_finished (msg);
        } else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
                g_clear_error (&error);
                io->io_source = soup_message_io_data_get_source (io, G_OBJECT (msg),
@@ -867,8 +837,8 @@ soup_message_io_run (SoupMessage *msg,
                                       soup_client_message_io_data_get_priority (client_io));
                g_source_attach (io->io_source, g_main_context_get_thread_default ());
        } else {
-               if (soup_message_get_io_data (msg) == client_io)
-                       soup_message_io_finish (msg, error);
+               if (get_io_data (msg) == client_io)
+                       soup_message_io_http1_finish (msg, error);
                g_error_free (error);
 
        }
@@ -876,12 +846,12 @@ soup_message_io_run (SoupMessage *msg,
        g_object_unref (msg);
 }
 
-gboolean
-soup_message_io_run_until_read (SoupMessage  *msg,
+static gboolean
+soup_message_io_http1_run_until_read (SoupMessage  *msg,
                                GCancellable *cancellable,
                                GError      **error)
 {
-       SoupClientMessageIOData *io = soup_message_get_io_data (msg);
+       SoupMessageIOHTTP1 *io = get_io_data (msg);
 
        if (io_run_until (msg, TRUE,
                          SOUP_MESSAGE_IO_STATE_BODY,
@@ -889,8 +859,8 @@ soup_message_io_run_until_read (SoupMessage  *msg,
                          cancellable, error))
                return TRUE;
 
-       if (soup_message_get_io_data (msg) == io)
-               soup_message_io_finish (msg, *error);
+       if (get_io_data (msg) == io)
+               soup_message_io_http1_finish (msg, *error);
 
        return FALSE;
 }
@@ -912,7 +882,7 @@ static void
 io_run_until_read_async (SoupMessage *msg,
                          GTask       *task)
 {
-        SoupClientMessageIOData *client_io = soup_message_get_io_data (msg);
+        SoupMessageIOHTTP1 *client_io = get_io_data (msg);
        SoupMessageIOData *io = &client_io->base;
         GError *error = NULL;
 
@@ -942,15 +912,15 @@ io_run_until_read_async (SoupMessage *msg,
                 return;
         }
 
-        if (soup_message_get_io_data (msg) == client_io)
-                soup_message_io_finish (msg, error);
+        if (get_io_data (msg) == client_io)
+                soup_message_io_http1_finish (msg, error);
 
         g_task_return_error (task, error);
         g_object_unref (task);
 }
 
-void
-soup_message_io_run_until_read_async (SoupMessage        *msg,
+static void
+soup_message_io_http1_run_until_read_async (SoupMessage        *msg,
                                      int                 io_priority,
                                       GCancellable       *cancellable,
                                       GAsyncReadyCallback callback,
@@ -963,21 +933,13 @@ soup_message_io_run_until_read_async (SoupMessage        *msg,
         io_run_until_read_async (msg, task);
 }
 
-gboolean
-soup_message_io_run_until_read_finish (SoupMessage  *msg,
-                                       GAsyncResult *result,
-                                       GError      **error)
-{
-        return g_task_propagate_boolean (G_TASK (result), error);
-}
-
-gboolean
-soup_message_io_run_until_finish (SoupMessage   *msg,
+static gboolean
+soup_message_io_http1_run_until_finish (SoupMessage   *msg,
                                  gboolean       blocking,
                                  GCancellable  *cancellable,
                                  GError       **error)
 {
-       SoupClientMessageIOData *io = soup_message_get_io_data (msg);
+       SoupMessageIOHTTP1 *io = get_io_data (msg);
        gboolean success;
 
        g_object_ref (msg);
@@ -1000,17 +962,17 @@ static void
 client_stream_eof (SoupClientInputStream *stream, gpointer user_data)
 {
        SoupMessage *msg = user_data;
-       SoupClientMessageIOData *io = soup_message_get_io_data (msg);
+       SoupMessageIOHTTP1 *io = get_io_data (msg);
 
        if (io && io->base.read_state == SOUP_MESSAGE_IO_STATE_BODY)
                io->base.read_state = SOUP_MESSAGE_IO_STATE_BODY_DONE;
 }
 
-GInputStream *
-soup_message_io_get_response_istream (SoupMessage  *msg,
+static GInputStream *
+soup_message_io_http1_get_response_istream (SoupMessage  *msg,
                                      GError      **error)
 {
-       SoupClientMessageIOData *io = soup_message_get_io_data (msg);
+       SoupMessageIOHTTP1 *io = get_io_data (msg);
        GInputStream *client_stream;
 
        client_stream = soup_client_input_stream_new (io->base.body_istream, msg);
@@ -1020,14 +982,20 @@ soup_message_io_get_response_istream (SoupMessage  *msg,
        return client_stream;
 }
 
-void
-soup_message_send_request (SoupMessageQueueItem      *item,
-                          SoupMessageIOCompletionFn  completion_cb,
-                          gpointer                   user_data)
+SoupMessageIOHTTP1 *
+soup_message_io_http1_new (void)
+{
+       return g_object_new (SOUP_TYPE_MESSAGE_IO_HTTP1, NULL);
+}
+
+static void
+soup_message_io_http1_send_item (SoupMessageIOBackend *backend,
+                                 SoupMessageQueueItem *item,
+                                 SoupMessageIOCompletionFn completion_cb,
+                                 gpointer user_data)
 {
-       SoupClientMessageIOData *io;
+        SoupMessageIOHTTP1 *io = (SoupMessageIOHTTP1 *)backend;
 
-       io = g_slice_new0 (SoupClientMessageIOData);
        io->base.completion_cb = completion_cb;
        io->base.completion_data = user_data;
 
@@ -1052,49 +1020,83 @@ soup_message_send_request (SoupMessageQueueItem      *item,
 #ifdef HAVE_SYSPROF
        io->begin_time_nsec = SYSPROF_CAPTURE_CURRENT_TIME;
 #endif
-
-       soup_message_set_io_data (io->item->msg, io);
 }
 
-void
-soup_message_io_pause (SoupMessage *msg)
+
+static void
+soup_message_io_http1_pause (SoupMessage *msg)
 {
-       SoupClientMessageIOData *io = soup_message_get_io_data (msg);
+       SoupMessageIOHTTP1 *io = get_io_data (msg);
 
-       g_return_if_fail (io != NULL);
        g_return_if_fail (io->base.read_state < SOUP_MESSAGE_IO_STATE_BODY);
 
        soup_message_io_data_pause (&io->base);
 }
 
-void
-soup_message_io_unpause (SoupMessage *msg)
+static void
+soup_message_io_http1_unpause (SoupMessage *msg)
 {
-       SoupClientMessageIOData *io = soup_message_get_io_data (msg);
+       SoupMessageIOHTTP1 *io = get_io_data (msg);
 
-       g_return_if_fail (io != NULL);
        g_return_if_fail (io->base.read_state < SOUP_MESSAGE_IO_STATE_BODY);
        io->base.paused = FALSE;
 }
 
-/**
- * soup_message_io_in_progress:
- * @msg: a #SoupMessage
- *
- * Tests whether or not I/O is currently in progress on @msg.
- *
- * Returns: whether or not I/O is currently in progress.
- **/
-gboolean
-soup_message_io_in_progress (SoupMessage *msg)
+static gboolean
+soup_message_io_http1_in_progress (SoupMessage *msg)
+{
+       return TRUE; // True as long as this object is alive
+}
+
+static gboolean
+soup_message_io_http1_is_paused (SoupMessage *msg)
+{
+       SoupMessageIOHTTP1 *io = get_io_data (msg);
+
+       return io->base.paused;
+}
+
+static void
+soup_message_io_http1_finalize (GObject *object)
+{
+        SoupMessageIOHTTP1 *io = (SoupMessageIOHTTP1 *)object;
+
+        if (io->item) {
+               soup_message_set_io_data (io->item->msg, NULL);
+                g_clear_pointer (&io->item, soup_message_queue_item_unref);
+        }
+
+       soup_message_io_data_cleanup (&io->base);
+
+        G_OBJECT_CLASS (soup_message_io_http1_parent_class)->finalize (object);
+}
+
+static void
+soup_message_io_http1_init (SoupMessageIOHTTP1 *self)
 {
-       return soup_message_get_io_data (msg) != NULL;
 }
 
-gboolean
-soup_message_is_io_paused (SoupMessage *msg)
+static void
+soup_message_io_http1_class_init (SoupMessageIOHTTP1Class *klass)
 {
-       SoupClientMessageIOData *io = soup_message_get_io_data (msg);
+        GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
-       return io && io->base.paused;
+        gobject_class->finalize = soup_message_io_http1_finalize;
 }
+
+static void
+soup_message_io_http1_iface_init (SoupMessageIOBackendInterface *iface)
+{
+        iface->finished = soup_message_io_http1_finished;
+        iface->stolen = soup_message_io_http1_stolen;
+        iface->pause = soup_message_io_http1_pause;
+        iface->unpause = soup_message_io_http1_unpause;
+        iface->is_paused = soup_message_io_http1_is_paused;
+        iface->in_progress = soup_message_io_http1_in_progress;
+        iface->get_response_istream = soup_message_io_http1_get_response_istream;
+        iface->run = soup_message_io_http1_run;   
+        iface->run_until_read = soup_message_io_http1_run_until_read;
+        iface->run_until_finish = soup_message_io_http1_run_until_finish;
+        iface->run_until_read_async = soup_message_io_http1_run_until_read_async;
+        iface->send_item = soup_message_io_http1_send_item;
+}
\ No newline at end of file
diff --git a/libsoup/soup-message-io-http1.h b/libsoup/soup-message-io-http1.h
new file mode 100644
index 00000000..e044b92a
--- /dev/null
+++ b/libsoup/soup-message-io-http1.h
@@ -0,0 +1,33 @@
+/* soup-message-io-http1.h
+ *
+ * Copyright 2020 Igalia S.L.
+ *
+ * This file 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; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ */
+
+#pragma once
+
+#include "soup-message-io-backend.h"
+#include "soup-message-io-data.h"
+
+G_BEGIN_DECLS
+
+#define SOUP_TYPE_MESSAGE_IO_HTTP1 (soup_message_io_http1_get_type())
+G_DECLARE_FINAL_TYPE (SoupMessageIOHTTP1, soup_message_io_http1, SOUP, MESSAGE_IO_HTTP1, GObject)
+
+SoupMessageIOHTTP1 *soup_message_io_http1_new (void);
+
+G_END_DECLS
\ No newline at end of file
diff --git a/libsoup/soup-message-private.h b/libsoup/soup-message-private.h
index 05e0dcc9..11684ad8 100644
--- a/libsoup/soup-message-private.h
+++ b/libsoup/soup-message-private.h
@@ -8,6 +8,7 @@
 
 #include "soup-filter-input-stream.h"
 #include "soup-message.h"
+#include "soup-message-io-backend.h"
 #include "soup-message-io-data.h"
 #include "auth/soup-auth.h"
 #include "soup-content-processor.h"
@@ -33,10 +34,6 @@ typedef guint    (*SoupMessageParseHeadersFn)(SoupMessage      *msg,
                                              gpointer          user_data,
                                              GError          **error);
 
-void soup_message_send_request (SoupMessageQueueItem      *item,
-                               SoupMessageIOCompletionFn  completion_cb,
-                               gpointer                   user_data);
-
 /* Auth handling */
 void           soup_message_set_auth       (SoupMessage *msg,
                                            SoupAuth    *auth);
@@ -46,50 +43,6 @@ void           soup_message_set_proxy_auth (SoupMessage *msg,
 SoupAuth      *soup_message_get_proxy_auth (SoupMessage *msg);
 GUri          *soup_message_get_uri_for_auth (SoupMessage *msg);
 
-/* I/O */
-void       soup_message_io_run         (SoupMessage *msg,
-                                       gboolean     blocking);
-void       soup_message_io_finished    (SoupMessage *msg);
-void       soup_message_io_cleanup     (SoupMessage *msg);
-void       soup_message_io_pause       (SoupMessage *msg);
-void       soup_message_io_unpause     (SoupMessage *msg);
-gboolean   soup_message_is_io_paused   (SoupMessage *msg);
-gboolean   soup_message_io_in_progress (SoupMessage *msg);
-void       soup_message_io_stolen      (SoupMessage *msg);
-
-gboolean soup_message_io_read_headers          (SoupMessage           *msg,
-                                                SoupFilterInputStream *stream,
-                                                GByteArray            *buffer,
-                                                gboolean               blocking,
-                                                GCancellable          *cancellable,
-                                                GError               **error);
-
-gboolean soup_message_io_run_until_finish      (SoupMessage        *msg,
-                                                gboolean            blocking,
-                                                GCancellable       *cancellable,
-                                                GError            **error);
-
-gboolean soup_message_io_run_until_read        (SoupMessage        *msg,
-                                                GCancellable       *cancellable,
-                                                GError            **error);
-void     soup_message_io_run_until_read_async  (SoupMessage        *msg,
-                                               int                 io_priority,
-                                                GCancellable       *cancellable,
-                                                GAsyncReadyCallback callback,
-                                                gpointer            user_data);
-gboolean soup_message_io_run_until_read_finish (SoupMessage        *msg,
-                                                GAsyncResult       *result,
-                                                GError            **error);
-
-typedef gboolean (*SoupMessageSourceFunc) (SoupMessage *, gpointer);
-GSource *soup_message_io_get_source       (SoupMessage           *msg,
-                                          GCancellable          *cancellable,
-                                          SoupMessageSourceFunc  callback,
-                                          gpointer               user_data);
-
-GInputStream *soup_message_io_get_response_istream (SoupMessage  *msg,
-                                                   GError      **error);
-
 void soup_message_wrote_headers     (SoupMessage *msg);
 void soup_message_wrote_body_data   (SoupMessage *msg,
                                     gsize        chunk_size);
@@ -122,9 +75,10 @@ SoupConnection *soup_message_get_connection (SoupMessage    *msg);
 void            soup_message_set_connection (SoupMessage    *msg,
                                             SoupConnection *conn);
 
-SoupClientMessageIOData *soup_message_get_io_data (SoupMessage             *msg);
+SoupMessageIOBackend    *soup_message_get_io_data (SoupMessage             *msg);
 void                     soup_message_set_io_data (SoupMessage             *msg,
-                                                  SoupClientMessageIOData *io);
+                                                  SoupMessageIOBackend    *io);
+void                     soup_message_clear_io_data (SoupMessage           *msg);
 
 SoupContentSniffer *soup_message_get_content_sniffer    (SoupMessage        *msg);
 void                soup_message_set_content_sniffer    (SoupMessage        *msg,
diff --git a/libsoup/soup-message.c b/libsoup/soup-message.c
index 87adc6f4..748ce320 100644
--- a/libsoup/soup-message.c
+++ b/libsoup/soup-message.c
@@ -59,7 +59,7 @@ struct _SoupMessage {
 };
 
 typedef struct {
-       SoupClientMessageIOData *io_data;
+       SoupMessageIOBackend *io_data;
 
         SoupMessageHeaders *request_headers;
        SoupMessageHeaders *response_headers;
@@ -166,7 +166,7 @@ soup_message_finalize (GObject *object)
 
        soup_message_set_connection (msg, NULL);
 
-       soup_client_message_io_data_free (priv->io_data);
+        g_clear_object (&priv->io_data);
 
        g_clear_pointer (&priv->uri, g_uri_unref);
        g_clear_pointer (&priv->first_party, g_uri_unref);
@@ -2136,7 +2136,7 @@ soup_message_get_priority (SoupMessage *msg)
        return priv->priority;
 }
 
-SoupClientMessageIOData *
+SoupMessageIOBackend *
 soup_message_get_io_data (SoupMessage *msg)
 {
        SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
@@ -2144,13 +2144,22 @@ soup_message_get_io_data (SoupMessage *msg)
        return priv->io_data;
 }
 
+void
+soup_message_clear_io_data (SoupMessage *msg)
+{
+       SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
+
+        g_clear_object (&priv->io_data);
+}
+
 void
 soup_message_set_io_data (SoupMessage             *msg,
-                         SoupClientMessageIOData *io)
+                         SoupMessageIOBackend    *io)
 {
        SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
 
-       soup_client_message_io_data_free (priv->io_data);
+        g_assert (!priv->io_data);
+
        priv->io_data = io;
 }
 
@@ -2181,6 +2190,55 @@ soup_message_set_bytes_for_sniffing (SoupMessage *msg, gsize bytes)
        priv->bytes_for_sniffing = bytes;
 }
 
+static gint
+processing_stage_cmp (gconstpointer a,
+                      gconstpointer b)
+{
+       SoupProcessingStage stage_a = soup_content_processor_get_processing_stage (SOUP_CONTENT_PROCESSOR 
((gpointer)a));
+       SoupProcessingStage stage_b = soup_content_processor_get_processing_stage (SOUP_CONTENT_PROCESSOR 
((gpointer)b));
+
+       if (stage_a > stage_b)
+               return 1;
+       if (stage_a == stage_b)
+               return 0;
+       return -1;
+}
+
+GInputStream *
+soup_message_setup_body_istream (GInputStream *body_stream,
+                                SoupMessage *msg,
+                                SoupSession *session,
+                                SoupProcessingStage start_at_stage)
+{
+       GInputStream *istream;
+       GSList *p, *processors;
+
+       istream = g_object_ref (body_stream);
+
+       processors = soup_session_get_features (session, SOUP_TYPE_CONTENT_PROCESSOR);
+       processors = g_slist_sort (processors, processing_stage_cmp);
+
+       for (p = processors; p; p = p->next) {
+               GInputStream *wrapper;
+               SoupContentProcessor *processor;
+
+               processor = SOUP_CONTENT_PROCESSOR (p->data);
+               if (soup_message_disables_feature (msg, p->data) ||
+                   soup_content_processor_get_processing_stage (processor) < start_at_stage)
+                       continue;
+
+               wrapper = soup_content_processor_wrap_input (processor, istream, msg, NULL);
+               if (wrapper) {
+                       g_object_unref (istream);
+                       istream = wrapper;
+               }
+       }
+
+       g_slist_free (processors);
+
+       return istream;
+}
+
 GInputStream *
 soup_message_get_request_body_stream (SoupMessage *msg)
 {


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