[libsoup] Implement skip for SoupClientInputStream and SoupFilterInputStream



commit 12cfc749653ab2b869df2ec20c9b10e1264894e7
Author: Daniel Kolesa <dkolesa igalia com>
Date:   Mon Mar 8 17:56:13 2021 +0100

    Implement skip for SoupClientInputStream and SoupFilterInputStream
    
    this enables calling `g_input_stream_skip` on response body input
    streams and getting predictable behavior (i.e. read but without
    explicit storage)
    
    the `skip` implementation for body input stream was insufficient,
    resulting in the stream state never incrementing properly

 libsoup/soup-body-input-stream.c   | 26 +++++++++-----------------
 libsoup/soup-client-input-stream.c | 18 ++++++++++++++++++
 libsoup/soup-filter-input-stream.c | 24 +++++++++++++++++++++++-
 3 files changed, 50 insertions(+), 18 deletions(-)
---
diff --git a/libsoup/soup-body-input-stream.c b/libsoup/soup-body-input-stream.c
index 88ccd2ed..56a87cda 100644
--- a/libsoup/soup-body-input-stream.c
+++ b/libsoup/soup-body-input-stream.c
@@ -136,10 +136,13 @@ soup_body_input_stream_read_raw (SoupBodyInputStream  *bistream,
         SoupBodyInputStreamPrivate *priv = soup_body_input_stream_get_instance_private (bistream);
        gssize nread;
 
-       nread = g_pollable_stream_read (priv->base_stream,
-                                       buffer, count,
-                                       blocking,
-                                       cancellable, error);
+       if (!buffer && blocking)
+               nread = g_input_stream_skip (priv->base_stream, count, cancellable, error);
+       else
+               nread = g_pollable_stream_read (priv->base_stream,
+                                               buffer, count,
+                                               blocking,
+                                               cancellable, error);
        if (nread == 0) {
                priv->eof = TRUE;
                if (priv->encoding != SOUP_ENCODING_EOF) {
@@ -288,19 +291,8 @@ soup_body_input_stream_skip (GInputStream *stream,
                             GCancellable *cancellable,
                             GError      **error)
 {
-        SoupBodyInputStreamPrivate *priv = soup_body_input_stream_get_instance_private 
(SOUP_BODY_INPUT_STREAM(stream));
-       gssize skipped;
-
-       skipped = g_input_stream_skip (G_FILTER_INPUT_STREAM (stream)->base_stream,
-                                      MIN (count, priv->read_length),
-                                      cancellable, error);
-
-       if (skipped == 0)
-               priv->eof = TRUE;
-       else if (skipped > 0)
-               priv->pos += skipped;
-
-       return skipped;
+        return read_internal (stream, NULL, count, TRUE,
+                              cancellable, error);
 }
 
 static gssize
diff --git a/libsoup/soup-client-input-stream.c b/libsoup/soup-client-input-stream.c
index d3a75467..2b452fe5 100644
--- a/libsoup/soup-client-input-stream.c
+++ b/libsoup/soup-client-input-stream.c
@@ -111,6 +111,23 @@ soup_client_input_stream_read_fn (GInputStream  *stream,
        return nread;
 }
 
+static gssize
+soup_client_input_stream_skip (GInputStream  *stream,
+                               gsize          count,
+                               GCancellable  *cancellable,
+                               GError       **error)
+{
+        gssize nread;
+
+        nread = G_INPUT_STREAM_CLASS (soup_client_input_stream_parent_class)->
+                skip (stream, count, cancellable, error);
+
+        if (nread == 0)
+                g_signal_emit (stream, signals[SIGNAL_EOF], 0);
+
+        return nread;
+}
+
 static gssize
 soup_client_input_stream_read_nonblocking (GPollableInputStream  *stream,
                                           void                  *buffer,
@@ -233,6 +250,7 @@ soup_client_input_stream_class_init (SoupClientInputStreamClass *stream_class)
        object_class->get_property = soup_client_input_stream_get_property;
 
        input_stream_class->read_fn = soup_client_input_stream_read_fn;
+       input_stream_class->skip = soup_client_input_stream_skip;
        input_stream_class->close_fn = soup_client_input_stream_close_fn;
        input_stream_class->close_async = soup_client_input_stream_close_async;
        input_stream_class->close_finish = soup_client_input_stream_close_finish;
diff --git a/libsoup/soup-filter-input-stream.c b/libsoup/soup-filter-input-stream.c
index fd4466f1..d3af6b72 100644
--- a/libsoup/soup-filter-input-stream.c
+++ b/libsoup/soup-filter-input-stream.c
@@ -57,7 +57,8 @@ read_from_buf (SoupFilterInputStream *fstream, gpointer buffer, gsize count)
 
        if (buf->len < count)
                count = buf->len;
-       memcpy (buffer, buf->data, count);
+       if (buffer)
+               memcpy (buffer, buf->data, count);
 
        if (count == buf->len) {
                g_byte_array_free (buf, TRUE);
@@ -93,6 +94,26 @@ soup_filter_input_stream_read_fn (GInputStream  *stream,
        }
 }
 
+static gssize
+soup_filter_input_stream_skip (GInputStream  *stream,
+                               gsize          count,
+                               GCancellable  *cancellable,
+                               GError       **error)
+{
+        SoupFilterInputStream *fstream = SOUP_FILTER_INPUT_STREAM (stream);
+        SoupFilterInputStreamPrivate *priv = soup_filter_input_stream_get_instance_private (fstream);
+
+        if (!priv->in_read_until)
+                priv->need_more = FALSE;
+
+        if (priv->buf && !priv->in_read_until) {
+                return read_from_buf (fstream, NULL, count);
+        } else {
+                return g_input_stream_skip (G_FILTER_INPUT_STREAM (fstream)->base_stream,
+                                            count, cancellable, error);
+        }
+}
+
 static gboolean
 soup_filter_input_stream_is_readable (GPollableInputStream *stream)
 {
@@ -156,6 +177,7 @@ soup_filter_input_stream_class_init (SoupFilterInputStreamClass *stream_class)
        object_class->finalize = soup_filter_input_stream_finalize;
 
        input_stream_class->read_fn = soup_filter_input_stream_read_fn;
+       input_stream_class->skip = soup_filter_input_stream_skip;
 }
 
 static void


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