[libsoup] SoupBodyInputStream: make it seekable
- From: Sergio Villar Senin <svillar src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsoup] SoupBodyInputStream: make it seekable
- Date: Mon, 10 Sep 2012 15:07:34 +0000 (UTC)
commit f723ab8220488bcdbb639373631675a64b061d79
Author: Sergio Villar Senin <svillar igalia com>
Date: Tue Aug 7 20:16:01 2012 +0200
SoupBodyInputStream: make it seekable
SoupBodyInputStream implements now the GSeekable interface. It does not
longer require a SoupFilterInputStream as base stream unless the encoding is
SOUP_ENCODING_CHUNKED.
https://bugzilla.gnome.org/show_bug.cgi?id=665884
libsoup/soup-body-input-stream.c | 136 ++++++++++++++++++++++++++++++++++++-
libsoup/soup-body-input-stream.h | 6 +-
libsoup/soup-message-io.c | 2 +-
3 files changed, 136 insertions(+), 8 deletions(-)
---
diff --git a/libsoup/soup-body-input-stream.c b/libsoup/soup-body-input-stream.c
index ba4ce6a..fff0780 100644
--- a/libsoup/soup-body-input-stream.c
+++ b/libsoup/soup-body-input-stream.c
@@ -33,6 +33,8 @@ struct _SoupBodyInputStreamPrivate {
goffset read_length;
SoupBodyInputStreamState chunked_state;
gboolean eof;
+
+ goffset pos;
};
enum {
@@ -50,10 +52,13 @@ enum {
};
static void soup_body_input_stream_pollable_init (GPollableInputStreamInterface *pollable_interface, gpointer interface_data);
+static void soup_body_input_stream_seekable_init (GSeekableIface *seekable_interface);
G_DEFINE_TYPE_WITH_CODE (SoupBodyInputStream, soup_body_input_stream, G_TYPE_FILTER_INPUT_STREAM,
G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM,
- soup_body_input_stream_pollable_init))
+ soup_body_input_stream_pollable_init)
+ G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
+ soup_body_input_stream_seekable_init))
static void
soup_body_input_stream_init (SoupBodyInputStream *bistream)
@@ -258,6 +263,9 @@ read_internal (GInputStream *stream,
blocking, cancellable, error);
if (bistream->priv->read_length != -1 && nread > 0)
bistream->priv->read_length -= nread;
+
+ if (bistream->priv->encoding == SOUP_ENCODING_CONTENT_LENGTH)
+ bistream->priv->pos += nread;
return nread;
default:
@@ -266,6 +274,25 @@ read_internal (GInputStream *stream,
}
static gssize
+soup_body_input_stream_skip (GInputStream *stream,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SoupBodyInputStreamPrivate *priv = SOUP_BODY_INPUT_STREAM(stream)->priv;
+ gssize skipped;
+
+ skipped = g_input_stream_skip (G_FILTER_INPUT_STREAM (stream)->base_stream,
+ MIN (count, priv->read_length),
+ cancellable, error);
+
+ if (skipped != -1)
+ priv->pos += skipped;
+
+ return skipped;
+}
+
+static gssize
soup_body_input_stream_read_fn (GInputStream *stream,
void *buffer,
gsize count,
@@ -295,6 +322,15 @@ soup_body_input_stream_is_readable (GPollableInputStream *stream)
g_pollable_input_stream_is_readable (G_POLLABLE_INPUT_STREAM (bistream->priv->base_stream));
}
+static gboolean
+soup_body_input_stream_can_poll (GPollableInputStream *pollable)
+{
+ GInputStream *base_stream = SOUP_BODY_INPUT_STREAM (pollable)->priv->base_stream;
+
+ return G_IS_POLLABLE_INPUT_STREAM (base_stream) &&
+ g_pollable_input_stream_can_poll (G_POLLABLE_INPUT_STREAM (base_stream));
+}
+
static gssize
soup_body_input_stream_read_nonblocking (GPollableInputStream *stream,
void *buffer,
@@ -337,6 +373,7 @@ soup_body_input_stream_class_init (SoupBodyInputStreamClass *stream_class)
object_class->set_property = soup_body_input_stream_set_property;
object_class->get_property = soup_body_input_stream_get_property;
+ input_stream_class->skip = soup_body_input_stream_skip;
input_stream_class->read_fn = soup_body_input_stream_read_fn;
input_stream_class->close_fn = soup_body_input_stream_close_fn;
@@ -370,16 +407,107 @@ static void
soup_body_input_stream_pollable_init (GPollableInputStreamInterface *pollable_interface,
gpointer interface_data)
{
+ pollable_interface->can_poll = soup_body_input_stream_can_poll;
pollable_interface->is_readable = soup_body_input_stream_is_readable;
pollable_interface->read_nonblocking = soup_body_input_stream_read_nonblocking;
pollable_interface->create_source = soup_body_input_stream_create_source;
}
+static goffset
+soup_body_input_stream_tell (GSeekable *seekable)
+{
+ return SOUP_BODY_INPUT_STREAM (seekable)->priv->pos;
+}
+
+static gboolean
+soup_body_input_stream_can_seek (GSeekable *seekable)
+{
+ SoupBodyInputStreamPrivate *priv = SOUP_BODY_INPUT_STREAM (seekable)->priv;
+
+ return priv->encoding == SOUP_ENCODING_CONTENT_LENGTH
+ && G_IS_SEEKABLE (priv->base_stream)
+ && g_seekable_can_seek (G_SEEKABLE (priv->base_stream));
+}
+
+static gboolean
+soup_body_input_stream_seek (GSeekable *seekable,
+ goffset offset,
+ GSeekType type,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SoupBodyInputStreamPrivate *priv = SOUP_BODY_INPUT_STREAM (seekable)->priv;
+ goffset position, end_position;
+
+ end_position = priv->pos + priv->read_length;
+ switch (type) {
+ case G_SEEK_CUR:
+ position = priv->pos + offset;
+ break;
+ case G_SEEK_SET:
+ position = offset;
+ break;
+ case G_SEEK_END:
+ position = end_position + offset;
+ break;
+ default:
+ g_return_val_if_reached (FALSE);
+ }
+
+ if (position < 0 || position >= end_position) {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Invalid seek request"));
+ return FALSE;
+ }
+
+ if (!g_seekable_seek (G_SEEKABLE (priv->base_stream), position - priv->pos,
+ G_SEEK_CUR, cancellable, error))
+ return FALSE;
+
+ priv->pos = position;
+
+ return TRUE;
+}
+
+static gboolean
+soup_body_input_stream_can_truncate (GSeekable *seekable)
+{
+ return FALSE;
+}
+
+static gboolean
+soup_body_input_stream_truncate_fn (GSeekable *seekable,
+ goffset offset,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Cannot truncate SoupBodyInputStream"));
+ return FALSE;
+}
+
+static void
+soup_body_input_stream_seekable_init (GSeekableIface *seekable_interface)
+{
+ seekable_interface->tell = soup_body_input_stream_tell;
+ seekable_interface->can_seek = soup_body_input_stream_can_seek;
+ seekable_interface->seek = soup_body_input_stream_seek;
+ seekable_interface->can_truncate = soup_body_input_stream_can_truncate;
+ seekable_interface->truncate_fn = soup_body_input_stream_truncate_fn;
+}
+
GInputStream *
-soup_body_input_stream_new (SoupFilterInputStream *base_stream,
- SoupEncoding encoding,
- goffset content_length)
+soup_body_input_stream_new (GInputStream *base_stream,
+ SoupEncoding encoding,
+ goffset content_length)
{
+ if (encoding == SOUP_ENCODING_CHUNKED)
+ g_return_val_if_fail (SOUP_IS_FILTER_INPUT_STREAM (base_stream), NULL);
+
return g_object_new (SOUP_TYPE_BODY_INPUT_STREAM,
"base-stream", base_stream,
"close-base-stream", FALSE,
diff --git a/libsoup/soup-body-input-stream.h b/libsoup/soup-body-input-stream.h
index 9e0c08e..7732e5e 100644
--- a/libsoup/soup-body-input-stream.h
+++ b/libsoup/soup-body-input-stream.h
@@ -39,9 +39,9 @@ typedef struct {
GType soup_body_input_stream_get_type (void);
-GInputStream *soup_body_input_stream_new (SoupFilterInputStream *base_stream,
- SoupEncoding encoding,
- goffset content_length);
+GInputStream *soup_body_input_stream_new (GInputStream *base_stream,
+ SoupEncoding encoding,
+ goffset content_length);
G_END_DECLS
diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c
index 6924e20..52af22b 100644
--- a/libsoup/soup-message-io.c
+++ b/libsoup/soup-message-io.c
@@ -231,7 +231,7 @@ setup_body_istream (SoupMessage *msg)
GSList *d;
io->body_istream =
- soup_body_input_stream_new (io->istream,
+ soup_body_input_stream_new (G_INPUT_STREAM (io->istream),
io->read_encoding,
io->read_length);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]