summaryrefslogtreecommitdiff
path: root/libsoup/soup-body-input-stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'libsoup/soup-body-input-stream.c')
-rw-r--r--libsoup/soup-body-input-stream.c141
1 files changed, 135 insertions, 6 deletions
diff --git a/libsoup/soup-body-input-stream.c b/libsoup/soup-body-input-stream.c
index ba4ce6a6..62747446 100644
--- a/libsoup/soup-body-input-stream.c
+++ b/libsoup/soup-body-input-stream.c
@@ -16,7 +16,6 @@
#include "soup-body-input-stream.h"
#include "soup.h"
#include "soup-filter-input-stream.h"
-#include "soup-marshal.h"
typedef enum {
SOUP_BODY_INPUT_STREAM_STATE_CHUNK_SIZE,
@@ -33,6 +32,8 @@ struct _SoupBodyInputStreamPrivate {
goffset read_length;
SoupBodyInputStreamState chunked_state;
gboolean eof;
+
+ goffset pos;
};
enum {
@@ -50,10 +51,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 +262,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 +273,27 @@ 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 == 0)
+ priv->eof = TRUE;
+ else if (skipped > 0)
+ priv->pos += skipped;
+
+ return skipped;
+}
+
+static gssize
soup_body_input_stream_read_fn (GInputStream *stream,
void *buffer,
gsize count,
@@ -295,6 +323,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 +374,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;
@@ -346,7 +384,7 @@ soup_body_input_stream_class_init (SoupBodyInputStreamClass *stream_class)
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
- _soup_marshal_NONE__NONE,
+ NULL,
G_TYPE_NONE, 0);
g_object_class_install_property (
@@ -370,16 +408,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,