Blame libsoup/soup-body-input-stream.c

rpm-build 4f3c61
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
rpm-build 4f3c61
/*
rpm-build 4f3c61
 * soup-body-input-stream.c
rpm-build 4f3c61
 *
rpm-build 4f3c61
 * Copyright 2012 Red Hat, Inc.
rpm-build 4f3c61
 */
rpm-build 4f3c61
rpm-build 4f3c61
#ifdef HAVE_CONFIG_H
rpm-build 4f3c61
#include <config.h>
rpm-build 4f3c61
#endif
rpm-build 4f3c61
rpm-build 4f3c61
#include <stdlib.h>
rpm-build 4f3c61
rpm-build 4f3c61
#include <glib/gi18n-lib.h>
rpm-build 4f3c61
rpm-build 4f3c61
#include "soup-body-input-stream.h"
rpm-build 4f3c61
#include "soup.h"
rpm-build 4f3c61
#include "soup-filter-input-stream.h"
rpm-build 4f3c61
rpm-build 4f3c61
typedef enum {
rpm-build 4f3c61
	SOUP_BODY_INPUT_STREAM_STATE_CHUNK_SIZE,
rpm-build 4f3c61
	SOUP_BODY_INPUT_STREAM_STATE_CHUNK_END,
rpm-build 4f3c61
	SOUP_BODY_INPUT_STREAM_STATE_CHUNK,
rpm-build 4f3c61
	SOUP_BODY_INPUT_STREAM_STATE_TRAILERS,
rpm-build 4f3c61
	SOUP_BODY_INPUT_STREAM_STATE_DONE
rpm-build 4f3c61
} SoupBodyInputStreamState;
rpm-build 4f3c61
rpm-build 4f3c61
struct _SoupBodyInputStreamPrivate {
rpm-build 4f3c61
	GInputStream *base_stream;
rpm-build 4f3c61
rpm-build 4f3c61
	SoupEncoding  encoding;
rpm-build 4f3c61
	goffset       read_length;
rpm-build 4f3c61
	SoupBodyInputStreamState chunked_state;
rpm-build 4f3c61
	gboolean      eof;
rpm-build 4f3c61
rpm-build 4f3c61
	goffset       pos;
rpm-build 4f3c61
};
rpm-build 4f3c61
rpm-build 4f3c61
enum {
rpm-build 4f3c61
	CLOSED,
rpm-build 4f3c61
	LAST_SIGNAL
rpm-build 4f3c61
};
rpm-build 4f3c61
rpm-build 4f3c61
static guint signals[LAST_SIGNAL] = { 0 };
rpm-build 4f3c61
rpm-build 4f3c61
enum {
rpm-build 4f3c61
	PROP_0,
rpm-build 4f3c61
rpm-build 4f3c61
	PROP_ENCODING,
rpm-build 4f3c61
	PROP_CONTENT_LENGTH
rpm-build 4f3c61
};
rpm-build 4f3c61
rpm-build 4f3c61
static void soup_body_input_stream_pollable_init (GPollableInputStreamInterface *pollable_interface, gpointer interface_data);
rpm-build 4f3c61
static void soup_body_input_stream_seekable_init (GSeekableIface *seekable_interface);
rpm-build 4f3c61
rpm-build 4f3c61
G_DEFINE_TYPE_WITH_CODE (SoupBodyInputStream, soup_body_input_stream, G_TYPE_FILTER_INPUT_STREAM,
rpm-build 4f3c61
                         G_ADD_PRIVATE (SoupBodyInputStream)
rpm-build 4f3c61
			 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM,
rpm-build 4f3c61
						soup_body_input_stream_pollable_init)
rpm-build 4f3c61
			 G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
rpm-build 4f3c61
						soup_body_input_stream_seekable_init))
rpm-build 4f3c61
rpm-build 4f3c61
static void
rpm-build 4f3c61
soup_body_input_stream_init (SoupBodyInputStream *bistream)
rpm-build 4f3c61
{
rpm-build 4f3c61
	bistream->priv = soup_body_input_stream_get_instance_private (bistream);
rpm-build 4f3c61
	bistream->priv->encoding = SOUP_ENCODING_NONE;
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static void
rpm-build 4f3c61
soup_body_input_stream_constructed (GObject *object)
rpm-build 4f3c61
{
rpm-build 4f3c61
	SoupBodyInputStream *bistream = SOUP_BODY_INPUT_STREAM (object);
rpm-build 4f3c61
rpm-build 4f3c61
	bistream->priv->base_stream = g_filter_input_stream_get_base_stream (G_FILTER_INPUT_STREAM (bistream));
rpm-build 4f3c61
rpm-build 4f3c61
	if (bistream->priv->encoding == SOUP_ENCODING_NONE ||
rpm-build 4f3c61
	    (bistream->priv->encoding == SOUP_ENCODING_CONTENT_LENGTH &&
rpm-build 4f3c61
	     bistream->priv->read_length == 0))
rpm-build 4f3c61
		bistream->priv->eof = TRUE;
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static void
rpm-build 4f3c61
soup_body_input_stream_set_property (GObject *object, guint prop_id,
rpm-build 4f3c61
				     const GValue *value, GParamSpec *pspec)
rpm-build 4f3c61
{
rpm-build 4f3c61
	SoupBodyInputStream *bistream = SOUP_BODY_INPUT_STREAM (object);
rpm-build 4f3c61
rpm-build 4f3c61
	switch (prop_id) {
rpm-build 4f3c61
	case PROP_ENCODING:
rpm-build 4f3c61
		bistream->priv->encoding = g_value_get_enum (value);
rpm-build 4f3c61
		if (bistream->priv->encoding == SOUP_ENCODING_CHUNKED)
rpm-build 4f3c61
			bistream->priv->chunked_state = SOUP_BODY_INPUT_STREAM_STATE_CHUNK_SIZE;
rpm-build 4f3c61
		break;
rpm-build 4f3c61
	case PROP_CONTENT_LENGTH:
rpm-build 4f3c61
		bistream->priv->read_length = g_value_get_int64 (value);
rpm-build 4f3c61
		break;
rpm-build 4f3c61
	default:
rpm-build 4f3c61
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
rpm-build 4f3c61
		break;
rpm-build 4f3c61
	}
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static void
rpm-build 4f3c61
soup_body_input_stream_get_property (GObject *object, guint prop_id,
rpm-build 4f3c61
				     GValue *value, GParamSpec *pspec)
rpm-build 4f3c61
{
rpm-build 4f3c61
	SoupBodyInputStream *bistream = SOUP_BODY_INPUT_STREAM (object);
rpm-build 4f3c61
rpm-build 4f3c61
	switch (prop_id) {
rpm-build 4f3c61
	case PROP_ENCODING:
rpm-build 4f3c61
		g_value_set_enum (value, bistream->priv->encoding);
rpm-build 4f3c61
		break;
rpm-build 4f3c61
	default:
rpm-build 4f3c61
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
rpm-build 4f3c61
		break;
rpm-build 4f3c61
	}
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static gssize
rpm-build 4f3c61
soup_body_input_stream_read_raw (SoupBodyInputStream  *bistream,
rpm-build 4f3c61
				 void                 *buffer,
rpm-build 4f3c61
				 gsize                 count,
rpm-build 4f3c61
				 gboolean              blocking,
rpm-build 4f3c61
				 GCancellable         *cancellable,
rpm-build 4f3c61
				 GError              **error)
rpm-build 4f3c61
{
rpm-build 4f3c61
	gssize nread;
rpm-build 4f3c61
rpm-build 4f3c61
	nread = g_pollable_stream_read (bistream->priv->base_stream,
rpm-build 4f3c61
					buffer, count,
rpm-build 4f3c61
					blocking,
rpm-build 4f3c61
					cancellable, error);
rpm-build 4f3c61
	if (nread == 0) {
rpm-build 4f3c61
		bistream->priv->eof = TRUE;
rpm-build 4f3c61
		if (bistream->priv->encoding != SOUP_ENCODING_EOF) {
rpm-build 4f3c61
			g_set_error_literal (error, G_IO_ERROR,
rpm-build 4f3c61
					     G_IO_ERROR_PARTIAL_INPUT,
rpm-build 4f3c61
					     _("Connection terminated unexpectedly"));
rpm-build 4f3c61
			return -1;
rpm-build 4f3c61
		}
rpm-build 4f3c61
	}
rpm-build 4f3c61
	return nread;
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static gssize
rpm-build 4f3c61
soup_body_input_stream_read_chunked (SoupBodyInputStream  *bistream,
rpm-build 4f3c61
				     void                 *buffer,
rpm-build 4f3c61
				     gsize                 count,
rpm-build 4f3c61
				     gboolean              blocking,
rpm-build 4f3c61
				     GCancellable         *cancellable,
rpm-build 4f3c61
				     GError              **error)
rpm-build 4f3c61
{
rpm-build 4f3c61
	SoupFilterInputStream *fstream = SOUP_FILTER_INPUT_STREAM (bistream->priv->base_stream);
rpm-build 4f3c61
	char metabuf[128];
rpm-build 4f3c61
	gssize nread;
rpm-build 4f3c61
	gboolean got_line;
rpm-build 4f3c61
rpm-build 4f3c61
again:
rpm-build 4f3c61
	switch (bistream->priv->chunked_state) {
rpm-build 4f3c61
	case SOUP_BODY_INPUT_STREAM_STATE_CHUNK_SIZE:
rpm-build 4f3c61
		nread = soup_filter_input_stream_read_line (
rpm-build 4f3c61
			fstream, metabuf, sizeof (metabuf), blocking,
rpm-build 4f3c61
			&got_line, cancellable, error);
rpm-build 4f3c61
		if (nread <= 0)
rpm-build 4f3c61
			return nread;
rpm-build 4f3c61
		if (!got_line) {
rpm-build 4f3c61
			g_set_error_literal (error, G_IO_ERROR,
rpm-build 4f3c61
					     G_IO_ERROR_PARTIAL_INPUT,
rpm-build 4f3c61
					     _("Connection terminated unexpectedly"));
rpm-build 4f3c61
			return -1;
rpm-build 4f3c61
		}
rpm-build 4f3c61
rpm-build 4f3c61
		bistream->priv->read_length = strtoul (metabuf, NULL, 16);
rpm-build 4f3c61
		if (bistream->priv->read_length > 0)
rpm-build 4f3c61
			bistream->priv->chunked_state = SOUP_BODY_INPUT_STREAM_STATE_CHUNK;
rpm-build 4f3c61
		else
rpm-build 4f3c61
			bistream->priv->chunked_state = SOUP_BODY_INPUT_STREAM_STATE_TRAILERS;
rpm-build 4f3c61
		break;
rpm-build 4f3c61
rpm-build 4f3c61
	case SOUP_BODY_INPUT_STREAM_STATE_CHUNK:
rpm-build 4f3c61
		nread = soup_body_input_stream_read_raw (
rpm-build 4f3c61
			bistream, buffer,
rpm-build 4f3c61
			MIN (count, bistream->priv->read_length),
rpm-build 4f3c61
			blocking, cancellable, error);
rpm-build 4f3c61
		if (nread > 0) {
rpm-build 4f3c61
			bistream->priv->read_length -= nread;
rpm-build 4f3c61
			if (bistream->priv->read_length == 0)
rpm-build 4f3c61
				bistream->priv->chunked_state = SOUP_BODY_INPUT_STREAM_STATE_CHUNK_END;
rpm-build 4f3c61
		}
rpm-build 4f3c61
		return nread;
rpm-build 4f3c61
rpm-build 4f3c61
	case SOUP_BODY_INPUT_STREAM_STATE_CHUNK_END:
rpm-build 4f3c61
		nread = soup_filter_input_stream_read_line (
rpm-build 4f3c61
			SOUP_FILTER_INPUT_STREAM (bistream->priv->base_stream),
rpm-build 4f3c61
			metabuf, sizeof (metabuf), blocking,
rpm-build 4f3c61
			&got_line, cancellable, error);
rpm-build 4f3c61
		if (nread <= 0)
rpm-build 4f3c61
			return nread;
rpm-build 4f3c61
		if (!got_line) {
rpm-build 4f3c61
			g_set_error_literal (error, G_IO_ERROR,
rpm-build 4f3c61
					     G_IO_ERROR_PARTIAL_INPUT,
rpm-build 4f3c61
					     _("Connection terminated unexpectedly"));
rpm-build 4f3c61
			return -1;
rpm-build 4f3c61
		}
rpm-build 4f3c61
rpm-build 4f3c61
		bistream->priv->chunked_state = SOUP_BODY_INPUT_STREAM_STATE_CHUNK_SIZE;
rpm-build 4f3c61
		break;
rpm-build 4f3c61
rpm-build 4f3c61
	case SOUP_BODY_INPUT_STREAM_STATE_TRAILERS:
rpm-build 4f3c61
		nread = soup_filter_input_stream_read_line (
rpm-build 4f3c61
			fstream, buffer, count, blocking,
rpm-build 4f3c61
			&got_line, cancellable, error);
rpm-build 4f3c61
		if (nread <= 0)
rpm-build 4f3c61
			return nread;
rpm-build 4f3c61
rpm-build 4f3c61
		if (strncmp (buffer, "\r\n", nread) || strncmp (buffer, "\n", nread)) {
rpm-build 4f3c61
			bistream->priv->chunked_state = SOUP_BODY_INPUT_STREAM_STATE_DONE;
rpm-build 4f3c61
			bistream->priv->eof = TRUE;
rpm-build 4f3c61
		}
rpm-build 4f3c61
		break;
rpm-build 4f3c61
rpm-build 4f3c61
	case SOUP_BODY_INPUT_STREAM_STATE_DONE:
rpm-build 4f3c61
		return 0;
rpm-build 4f3c61
	}
rpm-build 4f3c61
rpm-build 4f3c61
	goto again;
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static gssize
rpm-build 4f3c61
read_internal (GInputStream  *stream,
rpm-build 4f3c61
	       void          *buffer,
rpm-build 4f3c61
	       gsize          count,
rpm-build 4f3c61
	       gboolean       blocking,
rpm-build 4f3c61
	       GCancellable  *cancellable,
rpm-build 4f3c61
	       GError       **error)
rpm-build 4f3c61
{
rpm-build 4f3c61
	SoupBodyInputStream *bistream = SOUP_BODY_INPUT_STREAM (stream);
rpm-build 4f3c61
	gssize nread;
rpm-build 4f3c61
rpm-build 4f3c61
	if (bistream->priv->eof)
rpm-build 4f3c61
		return 0;
rpm-build 4f3c61
rpm-build 4f3c61
	switch (bistream->priv->encoding) {
rpm-build 4f3c61
	case SOUP_ENCODING_NONE:
rpm-build 4f3c61
		return 0;
rpm-build 4f3c61
rpm-build 4f3c61
	case SOUP_ENCODING_CHUNKED:
rpm-build 4f3c61
		return soup_body_input_stream_read_chunked (bistream, buffer, count,
rpm-build 4f3c61
							    blocking, cancellable, error);
rpm-build 4f3c61
rpm-build 4f3c61
	case SOUP_ENCODING_CONTENT_LENGTH:
rpm-build 4f3c61
	case SOUP_ENCODING_EOF:
rpm-build 4f3c61
		if (bistream->priv->read_length != -1) {
rpm-build 4f3c61
			count = MIN (count, bistream->priv->read_length);
rpm-build 4f3c61
			if (count == 0)
rpm-build 4f3c61
				return 0;
rpm-build 4f3c61
		}
rpm-build 4f3c61
rpm-build 4f3c61
		nread = soup_body_input_stream_read_raw (bistream, buffer, count,
rpm-build 4f3c61
							 blocking, cancellable, error);
rpm-build 4f3c61
		if (bistream->priv->read_length != -1 && nread > 0)
rpm-build 4f3c61
			bistream->priv->read_length -= nread;
rpm-build 4f3c61
rpm-build 4f3c61
		if (bistream->priv->encoding == SOUP_ENCODING_CONTENT_LENGTH)
rpm-build 4f3c61
			bistream->priv->pos += nread;
rpm-build 4f3c61
		return nread;
rpm-build 4f3c61
rpm-build 4f3c61
	default:
rpm-build 4f3c61
		g_return_val_if_reached (-1);
rpm-build 4f3c61
	}
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static gssize
rpm-build 4f3c61
soup_body_input_stream_skip (GInputStream *stream,
rpm-build 4f3c61
			     gsize         count,
rpm-build 4f3c61
			     GCancellable *cancellable,
rpm-build 4f3c61
			     GError      **error)
rpm-build 4f3c61
{
rpm-build 4f3c61
	SoupBodyInputStreamPrivate *priv = SOUP_BODY_INPUT_STREAM(stream)->priv;
rpm-build 4f3c61
	gssize skipped;
rpm-build 4f3c61
rpm-build 4f3c61
	skipped = g_input_stream_skip (G_FILTER_INPUT_STREAM (stream)->base_stream,
rpm-build 4f3c61
				       MIN (count, priv->read_length),
rpm-build 4f3c61
				       cancellable, error);
rpm-build 4f3c61
rpm-build 4f3c61
	if (skipped == 0)
rpm-build 4f3c61
		priv->eof = TRUE;
rpm-build 4f3c61
	else if (skipped > 0)
rpm-build 4f3c61
		priv->pos += skipped;
rpm-build 4f3c61
rpm-build 4f3c61
	return skipped;
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static gssize
rpm-build 4f3c61
soup_body_input_stream_read_fn (GInputStream  *stream,
rpm-build 4f3c61
				void          *buffer,
rpm-build 4f3c61
				gsize          count,
rpm-build 4f3c61
				GCancellable  *cancellable,
rpm-build 4f3c61
				GError       **error)
rpm-build 4f3c61
{
rpm-build 4f3c61
	return read_internal (stream, buffer, count, TRUE,
rpm-build 4f3c61
			      cancellable, error);
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static gboolean
rpm-build 4f3c61
soup_body_input_stream_close_fn (GInputStream  *stream,
rpm-build 4f3c61
				 GCancellable  *cancellable,
rpm-build 4f3c61
				 GError       **error)
rpm-build 4f3c61
{
rpm-build 4f3c61
	g_signal_emit (stream, signals[CLOSED], 0);
rpm-build 4f3c61
rpm-build 4f3c61
	return G_INPUT_STREAM_CLASS (soup_body_input_stream_parent_class)->close_fn (stream, cancellable, error);
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static gboolean
rpm-build 4f3c61
soup_body_input_stream_is_readable (GPollableInputStream *stream)
rpm-build 4f3c61
{
rpm-build 4f3c61
	SoupBodyInputStream *bistream = SOUP_BODY_INPUT_STREAM (stream);
rpm-build 4f3c61
rpm-build 4f3c61
	return bistream->priv->eof ||
rpm-build 4f3c61
		g_pollable_input_stream_is_readable (G_POLLABLE_INPUT_STREAM (bistream->priv->base_stream));
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static gboolean
rpm-build 4f3c61
soup_body_input_stream_can_poll (GPollableInputStream *pollable)
rpm-build 4f3c61
{
rpm-build 4f3c61
	GInputStream *base_stream = SOUP_BODY_INPUT_STREAM (pollable)->priv->base_stream;
rpm-build 4f3c61
rpm-build 4f3c61
	return G_IS_POLLABLE_INPUT_STREAM (base_stream) &&
rpm-build 4f3c61
		g_pollable_input_stream_can_poll (G_POLLABLE_INPUT_STREAM (base_stream));
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static gssize
rpm-build 4f3c61
soup_body_input_stream_read_nonblocking (GPollableInputStream  *stream,
rpm-build 4f3c61
					 void                  *buffer,
rpm-build 4f3c61
					 gsize                  count,
rpm-build 4f3c61
					 GError               **error)
rpm-build 4f3c61
{
rpm-build 4f3c61
	return read_internal (G_INPUT_STREAM (stream), buffer, count, FALSE,
rpm-build 4f3c61
			      NULL, error);
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static GSource *
rpm-build 4f3c61
soup_body_input_stream_create_source (GPollableInputStream *stream,
rpm-build 4f3c61
				      GCancellable *cancellable)
rpm-build 4f3c61
{
rpm-build 4f3c61
	SoupBodyInputStream *bistream = SOUP_BODY_INPUT_STREAM (stream);
rpm-build 4f3c61
	GSource *base_source, *pollable_source;
rpm-build 4f3c61
rpm-build 4f3c61
	if (bistream->priv->eof)
rpm-build 4f3c61
		base_source = g_timeout_source_new (0);
rpm-build 4f3c61
	else
rpm-build 4f3c61
		base_source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (bistream->priv->base_stream), cancellable);
rpm-build 4f3c61
	g_source_set_dummy_callback (base_source);
rpm-build 4f3c61
rpm-build 4f3c61
	pollable_source = g_pollable_source_new (G_OBJECT (stream));
rpm-build 4f3c61
	g_source_add_child_source (pollable_source, base_source);
rpm-build 4f3c61
	g_source_unref (base_source);
rpm-build 4f3c61
rpm-build 4f3c61
	return pollable_source;
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static void
rpm-build 4f3c61
soup_body_input_stream_class_init (SoupBodyInputStreamClass *stream_class)
rpm-build 4f3c61
{
rpm-build 4f3c61
	GObjectClass *object_class = G_OBJECT_CLASS (stream_class);
rpm-build 4f3c61
	GInputStreamClass *input_stream_class = G_INPUT_STREAM_CLASS (stream_class);
rpm-build 4f3c61
rpm-build 4f3c61
	object_class->constructed = soup_body_input_stream_constructed;
rpm-build 4f3c61
	object_class->set_property = soup_body_input_stream_set_property;
rpm-build 4f3c61
	object_class->get_property = soup_body_input_stream_get_property;
rpm-build 4f3c61
rpm-build 4f3c61
	input_stream_class->skip = soup_body_input_stream_skip;
rpm-build 4f3c61
	input_stream_class->read_fn = soup_body_input_stream_read_fn;
rpm-build 4f3c61
	input_stream_class->close_fn = soup_body_input_stream_close_fn;
rpm-build 4f3c61
rpm-build 4f3c61
	signals[CLOSED] =
rpm-build 4f3c61
		g_signal_new ("closed",
rpm-build 4f3c61
			      G_OBJECT_CLASS_TYPE (object_class),
rpm-build 4f3c61
			      G_SIGNAL_RUN_LAST,
rpm-build 4f3c61
			      0,
rpm-build 4f3c61
			      NULL, NULL,
rpm-build 4f3c61
			      NULL,
rpm-build 4f3c61
			      G_TYPE_NONE, 0);
rpm-build 4f3c61
rpm-build 4f3c61
	g_object_class_install_property (
rpm-build 4f3c61
		object_class, PROP_ENCODING,
rpm-build 4f3c61
		g_param_spec_enum ("encoding",
rpm-build 4f3c61
				   "Encoding",
rpm-build 4f3c61
				   "Message body encoding",
rpm-build 4f3c61
				   SOUP_TYPE_ENCODING,
rpm-build 4f3c61
				   SOUP_ENCODING_NONE,
rpm-build 4f3c61
				   G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
rpm-build 4f3c61
	g_object_class_install_property (
rpm-build 4f3c61
		object_class, PROP_CONTENT_LENGTH,
rpm-build 4f3c61
		g_param_spec_int64 ("content-length",
rpm-build 4f3c61
				    "Content-Length",
rpm-build 4f3c61
				    "Message body Content-Length",
rpm-build 4f3c61
				    -1, G_MAXINT64, -1,
rpm-build 4f3c61
				    G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static void
rpm-build 4f3c61
soup_body_input_stream_pollable_init (GPollableInputStreamInterface *pollable_interface,
rpm-build 4f3c61
				 gpointer interface_data)
rpm-build 4f3c61
{
rpm-build 4f3c61
	pollable_interface->can_poll = soup_body_input_stream_can_poll;
rpm-build 4f3c61
	pollable_interface->is_readable = soup_body_input_stream_is_readable;
rpm-build 4f3c61
	pollable_interface->read_nonblocking = soup_body_input_stream_read_nonblocking;
rpm-build 4f3c61
	pollable_interface->create_source = soup_body_input_stream_create_source;
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static goffset
rpm-build 4f3c61
soup_body_input_stream_tell (GSeekable *seekable)
rpm-build 4f3c61
{
rpm-build 4f3c61
	return SOUP_BODY_INPUT_STREAM (seekable)->priv->pos;
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static gboolean
rpm-build 4f3c61
soup_body_input_stream_can_seek (GSeekable *seekable)
rpm-build 4f3c61
{
rpm-build 4f3c61
	SoupBodyInputStreamPrivate *priv = SOUP_BODY_INPUT_STREAM (seekable)->priv;
rpm-build 4f3c61
rpm-build 4f3c61
	return priv->encoding == SOUP_ENCODING_CONTENT_LENGTH
rpm-build 4f3c61
		&& G_IS_SEEKABLE (priv->base_stream)
rpm-build 4f3c61
		&& g_seekable_can_seek (G_SEEKABLE (priv->base_stream));
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static gboolean
rpm-build 4f3c61
soup_body_input_stream_seek (GSeekable     *seekable,
rpm-build 4f3c61
			     goffset        offset,
rpm-build 4f3c61
			     GSeekType      type,
rpm-build 4f3c61
			     GCancellable  *cancellable,
rpm-build 4f3c61
			     GError       **error)
rpm-build 4f3c61
{
rpm-build 4f3c61
	SoupBodyInputStreamPrivate *priv = SOUP_BODY_INPUT_STREAM (seekable)->priv;
rpm-build 4f3c61
	goffset position, end_position;
rpm-build 4f3c61
rpm-build 4f3c61
	end_position = priv->pos + priv->read_length;
rpm-build 4f3c61
	switch (type) {
rpm-build 4f3c61
	case G_SEEK_CUR:
rpm-build 4f3c61
		position = priv->pos + offset;
rpm-build 4f3c61
		break;
rpm-build 4f3c61
	case G_SEEK_SET:
rpm-build 4f3c61
		position = offset;
rpm-build 4f3c61
		break;
rpm-build 4f3c61
	case G_SEEK_END:
rpm-build 4f3c61
		position = end_position + offset;
rpm-build 4f3c61
		break;
rpm-build 4f3c61
	default:
rpm-build 4f3c61
		g_return_val_if_reached (FALSE);
rpm-build 4f3c61
	}
rpm-build 4f3c61
rpm-build 4f3c61
	if (position < 0 || position >= end_position) {
rpm-build 4f3c61
		g_set_error_literal (error,
rpm-build 4f3c61
				     G_IO_ERROR,
rpm-build 4f3c61
				     G_IO_ERROR_INVALID_ARGUMENT,
rpm-build 4f3c61
				     _("Invalid seek request"));
rpm-build 4f3c61
		return FALSE;
rpm-build 4f3c61
	}
rpm-build 4f3c61
rpm-build 4f3c61
	if (!g_seekable_seek (G_SEEKABLE (priv->base_stream), position - priv->pos,
rpm-build 4f3c61
			      G_SEEK_CUR, cancellable, error))
rpm-build 4f3c61
		return FALSE;
rpm-build 4f3c61
rpm-build 4f3c61
	priv->pos = position;
rpm-build 4f3c61
rpm-build 4f3c61
	return TRUE;
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static gboolean
rpm-build 4f3c61
soup_body_input_stream_can_truncate (GSeekable *seekable)
rpm-build 4f3c61
{
rpm-build 4f3c61
	return FALSE;
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static gboolean
rpm-build 4f3c61
soup_body_input_stream_truncate_fn (GSeekable     *seekable,
rpm-build 4f3c61
				    goffset        offset,
rpm-build 4f3c61
				    GCancellable  *cancellable,
rpm-build 4f3c61
				    GError       **error)
rpm-build 4f3c61
{
rpm-build 4f3c61
	g_set_error_literal (error,
rpm-build 4f3c61
			     G_IO_ERROR,
rpm-build 4f3c61
			     G_IO_ERROR_NOT_SUPPORTED,
rpm-build 4f3c61
			     _("Cannot truncate SoupBodyInputStream"));
rpm-build 4f3c61
	return FALSE;
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
static void
rpm-build 4f3c61
soup_body_input_stream_seekable_init (GSeekableIface *seekable_interface)
rpm-build 4f3c61
{
rpm-build 4f3c61
	seekable_interface->tell         = soup_body_input_stream_tell;
rpm-build 4f3c61
	seekable_interface->can_seek     = soup_body_input_stream_can_seek;
rpm-build 4f3c61
	seekable_interface->seek         = soup_body_input_stream_seek;
rpm-build 4f3c61
	seekable_interface->can_truncate = soup_body_input_stream_can_truncate;
rpm-build 4f3c61
	seekable_interface->truncate_fn  = soup_body_input_stream_truncate_fn;
rpm-build 4f3c61
}
rpm-build 4f3c61
rpm-build 4f3c61
GInputStream *
rpm-build 4f3c61
soup_body_input_stream_new (GInputStream *base_stream,
rpm-build 4f3c61
			    SoupEncoding  encoding,
rpm-build 4f3c61
			    goffset       content_length)
rpm-build 4f3c61
{
rpm-build 4f3c61
	if (encoding == SOUP_ENCODING_CHUNKED)
rpm-build 4f3c61
		g_return_val_if_fail (SOUP_IS_FILTER_INPUT_STREAM (base_stream), NULL);
rpm-build 4f3c61
rpm-build 4f3c61
	return g_object_new (SOUP_TYPE_BODY_INPUT_STREAM,
rpm-build 4f3c61
			     "base-stream", base_stream,
rpm-build 4f3c61
			     "close-base-stream", FALSE,
rpm-build 4f3c61
			     "encoding", encoding,
rpm-build 4f3c61
			     "content-length", content_length,
rpm-build 4f3c61
			     NULL);
rpm-build 4f3c61
}