[libsoup/giobased: 7/11] a bit messy, but push chunked encoding into sos



commit 0f32f7537aa0440e0a826d1f3b6647f1b9eb7fc0
Author: Dan Winship <danw gnome org>
Date:   Thu Dec 9 22:27:09 2010 +0100

    a bit messy, but push chunked encoding into sos

 libsoup/Makefile.am          |    2 +
 libsoup/soup-message-io.c    |  138 +++++-----------------
 libsoup/soup-output-stream.c |  265 ++++++++++++++++++++++++++++++++++++++++++
 libsoup/soup-output-stream.h |   55 +++++++++
 4 files changed, 353 insertions(+), 107 deletions(-)
---
diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am
index aec7948..951a6b9 100644
--- a/libsoup/Makefile.am
+++ b/libsoup/Makefile.am
@@ -154,6 +154,8 @@ libsoup_2_4_la_SOURCES =		\
 	soup-method.c     		\
 	soup-misc.c     		\
 	soup-multipart.c	     	\
+	soup-output-stream.h		\
+	soup-output-stream.c		\
 	soup-password-manager.c		\
 	soup-path-map.h     		\
 	soup-path-map.c     		\
diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c
index 4d66329..444ec2e 100644
--- a/libsoup/soup-message-io.c
+++ b/libsoup/soup-message-io.c
@@ -18,6 +18,7 @@
 #include "soup-message-private.h"
 #include "soup-message-queue.h"
 #include "soup-misc.h"
+#include "soup-output-stream.h"
 #include "soup-socket.h"
 #include "soup-ssl.h"
 
@@ -31,9 +32,6 @@ typedef enum {
 	SOUP_MESSAGE_IO_STATE_HEADERS,
 	SOUP_MESSAGE_IO_STATE_BLOCKING,
 	SOUP_MESSAGE_IO_STATE_BODY,
-	SOUP_MESSAGE_IO_STATE_CHUNK_SIZE,
-	SOUP_MESSAGE_IO_STATE_CHUNK,
-	SOUP_MESSAGE_IO_STATE_CHUNK_END,
 	SOUP_MESSAGE_IO_STATE_TRAILERS,
 	SOUP_MESSAGE_IO_STATE_FINISHING,
 	SOUP_MESSAGE_IO_STATE_DONE
@@ -51,7 +49,7 @@ typedef struct {
 
 	SoupSocket           *sock;
 	SoupInputStream      *istream;
-	GOutputStream        *ostream;
+	SoupOutputStream     *ostream;
 	GMainContext         *async_context;
 	gboolean              blocking;
 
@@ -181,7 +179,7 @@ soup_message_io_finished (SoupMessage *msg)
 }
 
 static gboolean io_read (SoupInputStream *stream, SoupMessage *msg);
-static gboolean io_write (GOutputStream *stream, SoupMessage *msg);
+static gboolean io_write (SoupOutputStream *stream, SoupMessage *msg);
 
 static gboolean
 request_is_idempotent (SoupMessage *msg)
@@ -551,7 +549,7 @@ write_data (SoupMessage *msg, const char *data, guint len, gboolean body)
 {
 	SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
 	SoupMessageIOData *io = priv->io_data;
-	gsize nwrote;
+	gssize nwrote;
 	GError *error = NULL;
 	SoupBuffer *chunk;
 	const char *start;
@@ -561,18 +559,12 @@ write_data (SoupMessage *msg, const char *data, guint len, gboolean body)
 		return FALSE;
 	}
 
-	while (len > io->written) {
-		if (io->blocking) {
-			nwrote = g_output_stream_write (io->ostream,
-							data + io->written,
-							len - io->written,
-							io->cancellable, &error);
-		} else {
-			nwrote = g_pollable_output_stream_write_nonblocking (
-				G_POLLABLE_OUTPUT_STREAM (io->ostream),
-				data + io->written, len - io->written,
-				io->cancellable, &error);
-		}
+	do {
+		nwrote = soup_output_stream_write (io->ostream,
+						   data + io->written,
+						   len - io->written,
+						   io->blocking,
+						   io->cancellable, &error);
 
 		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
 			g_error_free (error);
@@ -598,21 +590,12 @@ write_data (SoupMessage *msg, const char *data, guint len, gboolean body)
 			soup_buffer_free (chunk);
 			SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
 		}
-	}
+	} while (len > io->written);
 
 	io->written = 0;
 	return TRUE;
 }
 
-static inline SoupMessageIOState
-io_body_state (SoupEncoding encoding)
-{
-	if (encoding == SOUP_ENCODING_CHUNKED)
-		return SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
-	else
-		return SOUP_MESSAGE_IO_STATE_BODY;
-}
-
 /*
  * There are two request/response formats: the basic request/response,
  * possibly with one or more unsolicited informational responses (such
@@ -640,7 +623,7 @@ io_body_state (SoupEncoding encoding)
  */
 
 static gboolean
-io_write (GOutputStream *stream, SoupMessage *msg)
+io_write (SoupOutputStream *stream, SoupMessage *msg)
 {
 	SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
 	SoupMessageIOData *io = priv->io_data;
@@ -680,6 +663,9 @@ io_write (GOutputStream *stream, SoupMessage *msg)
 			io->write_length = soup_message_headers_get_content_length (hdrs);
 		}
 
+		soup_output_stream_set_encoding (io->ostream,
+						 io->write_encoding);
+
 		if (io->mode == SOUP_MESSAGE_IO_SERVER &&
 		    SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
 			if (msg->status_code == SOUP_STATUS_CONTINUE) {
@@ -702,7 +688,7 @@ io_write (GOutputStream *stream, SoupMessage *msg)
 			io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
 			io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
 		} else {
-			io->write_state = io_body_state (io->write_encoding);
+			io->write_state = SOUP_MESSAGE_IO_STATE_BODY;
 
 			/* If the client was waiting for a Continue
 			 * but we sent something else, then they're
@@ -736,7 +722,9 @@ io_write (GOutputStream *stream, SoupMessage *msg)
 
 
 	case SOUP_MESSAGE_IO_STATE_BODY:
-		if (!io->write_length && io->write_encoding != SOUP_ENCODING_EOF) {
+		if (!io->write_length &&
+		    io->write_encoding != SOUP_ENCODING_EOF &&
+		    io->write_encoding != SOUP_ENCODING_CHUNKED) {
 		wrote_body:
 			io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
 
@@ -752,8 +740,12 @@ io_write (GOutputStream *stream, SoupMessage *msg)
 				soup_message_io_pause (msg);
 				return FALSE;
 			}
-			if (io->write_chunk->length > io->write_length &&
-			    io->write_encoding != SOUP_ENCODING_EOF) {
+			if (io->write_encoding == SOUP_ENCODING_EOF) {
+				if (!io->write_chunk->length)
+					goto wrote_body;
+			} else if (io->write_encoding == SOUP_ENCODING_CHUNKED) {
+				io->write_length = io->write_chunk->length;
+			} else if (io->write_chunk->length > io->write_length) {
 				/* App is trying to write more than it
 				 * claimed it would; we have to truncate.
 				 */
@@ -762,95 +754,27 @@ io_write (GOutputStream *stream, SoupMessage *msg)
 								   0, io->write_length);
 				soup_buffer_free (io->write_chunk);
 				io->write_chunk = truncated;
-			} else if (io->write_encoding == SOUP_ENCODING_EOF &&
-				   !io->write_chunk->length)
-				goto wrote_body;
-		}
-
-		if (!write_data (msg, io->write_chunk->data,
-				 io->write_chunk->length, TRUE))
-			return FALSE;
-
-		if (io->mode == SOUP_MESSAGE_IO_SERVER)
-			soup_message_body_wrote_chunk (io->write_body, io->write_chunk);
-		io->write_body_offset += io->write_chunk->length;
-		soup_buffer_free (io->write_chunk);
-		io->write_chunk = NULL;
-
-		SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
-		soup_message_wrote_chunk (msg);
-		SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
-		break;
-
-	case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
-		if (!io->write_chunk) {
-			io->write_chunk = soup_message_body_get_chunk (io->write_body, io->write_body_offset);
-			if (!io->write_chunk) {
-				soup_message_io_pause (msg);
-				return FALSE;
 			}
-			g_string_append_printf (io->write_buf, "%lx\r\n",
-						(unsigned long) io->write_chunk->length);
-			io->write_body_offset += io->write_chunk->length;
-		}
-
-		if (!write_data (msg, io->write_buf->str,
-				 io->write_buf->len, FALSE))
-			return FALSE;
-
-		g_string_truncate (io->write_buf, 0);
-
-		if (io->write_chunk->length == 0) {
-			/* The last chunk has no CHUNK_END... */
-			io->write_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
-			break;
 		}
 
-		io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK;
-		/* fall through */
-
-
-	case SOUP_MESSAGE_IO_STATE_CHUNK:
 		if (!write_data (msg, io->write_chunk->data,
 				 io->write_chunk->length, TRUE))
 			return FALSE;
 
+		if (io->write_chunk->length == 0)
+			goto wrote_body;
+
 		if (io->mode == SOUP_MESSAGE_IO_SERVER)
 			soup_message_body_wrote_chunk (io->write_body, io->write_chunk);
+		io->write_body_offset += io->write_chunk->length;
 		soup_buffer_free (io->write_chunk);
 		io->write_chunk = NULL;
 
-		io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
-
 		SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
 		soup_message_wrote_chunk (msg);
 		SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
-
-		/* fall through */
-
-
-	case SOUP_MESSAGE_IO_STATE_CHUNK_END:
-		if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
-				 SOUP_MESSAGE_IO_EOL_LEN, FALSE))
-			return FALSE;
-
-		io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
 		break;
 
-
-	case SOUP_MESSAGE_IO_STATE_TRAILERS:
-		if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
-				 SOUP_MESSAGE_IO_EOL_LEN, FALSE))
-			return FALSE;
-
-		io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
-
-		SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
-		soup_message_wrote_body (msg);
-		SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
-		/* fall through */
-
-
 	case SOUP_MESSAGE_IO_STATE_FINISHING:
 		if (io->write_source) {
 			g_source_destroy (io->write_source);
@@ -959,7 +883,7 @@ io_read (SoupInputStream *stream, SoupMessage *msg)
 				io->read_state =
 					SOUP_MESSAGE_IO_STATE_BLOCKING;
 				io->write_state =
-					io_body_state (io->write_encoding);
+					SOUP_MESSAGE_IO_STATE_BODY;
 			} else {
 				/* Just stay in HEADERS */
 				io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
@@ -1100,7 +1024,7 @@ new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
 	iostream = soup_socket_get_iostream (sock);
 	if (iostream) {
 		io->istream = soup_input_stream_new (g_io_stream_get_input_stream (iostream));
-		io->ostream = g_io_stream_get_output_stream (iostream);
+		io->ostream = soup_output_stream_new (g_io_stream_get_output_stream (iostream));
 	}
 	g_object_get (io->sock,
 		      SOUP_SOCKET_FLAG_NONBLOCKING, &non_blocking,
diff --git a/libsoup/soup-output-stream.c b/libsoup/soup-output-stream.c
new file mode 100644
index 0000000..fee3227
--- /dev/null
+++ b/libsoup/soup-output-stream.c
@@ -0,0 +1,265 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-output-stream.c
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gio/gio.h>
+
+#include "soup-output-stream.h"
+#include "soup-message-headers.h"
+
+typedef enum {
+	SOUP_OUTPUT_STREAM_STATE_CHUNK_SIZE,
+	SOUP_OUTPUT_STREAM_STATE_CHUNK_END,
+	SOUP_OUTPUT_STREAM_STATE_CHUNK,
+	SOUP_OUTPUT_STREAM_STATE_TRAILERS,
+	SOUP_OUTPUT_STREAM_STATE_DONE
+} SoupOutputStreamState;
+
+struct _SoupOutputStreamPrivate {
+	GOutputStream *base_stream;
+	char           buf[20];
+
+	SoupEncoding   encoding;
+	goffset        write_length;
+	SoupOutputStreamState chunked_state;
+};
+
+static void soup_output_stream_pollable_init (GPollableOutputStreamInterface *pollable_interface, gpointer interface_data);
+
+G_DEFINE_TYPE_WITH_CODE (SoupOutputStream, soup_output_stream, G_TYPE_FILTER_OUTPUT_STREAM,
+			 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM,
+						soup_output_stream_pollable_init))
+
+
+static void
+soup_output_stream_init (SoupOutputStream *stream)
+{
+	stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
+						    SOUP_TYPE_OUTPUT_STREAM,
+						    SoupOutputStreamPrivate);
+}
+
+static void
+constructed (GObject *object)
+{
+	SoupOutputStream *sstream = SOUP_OUTPUT_STREAM (object);
+
+	sstream->priv->base_stream = g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (sstream));
+}
+
+static gssize
+soup_output_stream_write_raw (SoupOutputStream  *sstream,
+			      const void        *buffer,
+			      gsize              count,
+			      gboolean           blocking,
+			      GCancellable      *cancellable,
+			      GError           **error)
+{
+	if (blocking) {
+		return g_output_stream_write (sstream->priv->base_stream,
+					      buffer, count,
+					      cancellable, error);
+	} else {
+		return g_pollable_output_stream_write_nonblocking (
+			G_POLLABLE_OUTPUT_STREAM (sstream->priv->base_stream),
+			buffer, count, cancellable, error);
+	}
+}
+
+static gssize
+soup_output_stream_write_chunked (SoupOutputStream  *sstream,
+				  const void        *buffer,
+				  gsize              count,
+				  gboolean           blocking,
+				  GCancellable      *cancellable,
+				  GError           **error)
+{
+	char *buf = sstream->priv->buf;
+	gssize nwrote, len;
+
+again:
+	len = strlen (buf);
+	if (len) {
+		nwrote = soup_output_stream_write_raw (sstream, buf, len,
+						       blocking, cancellable,
+						       error);
+		if (nwrote < 0)
+			return nwrote;
+		memmove (buf, buf + nwrote, len + 1 - nwrote);
+		goto again;
+	}
+
+	switch (sstream->priv->chunked_state) {
+	case SOUP_OUTPUT_STREAM_STATE_CHUNK_SIZE:
+		snprintf (buf, sizeof (sstream->priv->buf),
+			  "%lx\r\n", (gulong)count);
+		len = strlen (buf);
+
+		if (count > 0)
+			sstream->priv->chunked_state = SOUP_OUTPUT_STREAM_STATE_CHUNK;
+		else
+			sstream->priv->chunked_state = SOUP_OUTPUT_STREAM_STATE_TRAILERS;
+		break;
+
+	case SOUP_OUTPUT_STREAM_STATE_CHUNK:
+		nwrote = soup_output_stream_write_raw (sstream, buffer, count,
+						       blocking, cancellable,
+						       error);
+		if (nwrote < (gssize)count)
+			return nwrote;
+
+		sstream->priv->chunked_state = SOUP_OUTPUT_STREAM_STATE_CHUNK_END;
+		break;
+
+	case SOUP_OUTPUT_STREAM_STATE_CHUNK_END:
+		strncpy (buf, "\r\n", sizeof (sstream->priv->buf));
+		len = 2;
+		sstream->priv->chunked_state = SOUP_OUTPUT_STREAM_STATE_DONE;
+		break;
+
+	case SOUP_OUTPUT_STREAM_STATE_TRAILERS:
+		strncpy (buf, "\r\n", sizeof (sstream->priv->buf));
+		len = 2;
+		sstream->priv->chunked_state = SOUP_OUTPUT_STREAM_STATE_DONE;
+		break;
+
+	case SOUP_OUTPUT_STREAM_STATE_DONE:
+		sstream->priv->chunked_state = SOUP_OUTPUT_STREAM_STATE_CHUNK_SIZE;
+		return count;
+	}
+
+	goto again;
+}
+
+static gssize
+soup_output_stream_write_fn (GOutputStream  *stream,
+			     const void     *buffer,
+			     gsize           count,
+			     GCancellable   *cancellable,
+			     GError        **error)
+{
+	SoupOutputStream *sstream = SOUP_OUTPUT_STREAM (stream);
+
+	switch (sstream->priv->encoding) {
+	case SOUP_ENCODING_CHUNKED:
+		return soup_output_stream_write_chunked (sstream, buffer, count,
+							 TRUE, cancellable,
+							 error);
+
+	default:
+		return soup_output_stream_write_raw (sstream, buffer, count,
+						     TRUE, cancellable, error);
+	}
+}
+
+static gboolean
+soup_output_stream_is_writable (GPollableOutputStream *stream)
+{
+	SoupOutputStream *sstream = SOUP_OUTPUT_STREAM (stream);
+
+	return g_pollable_output_stream_is_writable (G_POLLABLE_OUTPUT_STREAM (sstream->priv->base_stream));
+}
+
+static GSource *
+soup_output_stream_create_source (GPollableOutputStream *stream,
+				  GCancellable *cancellable)
+{
+	SoupOutputStream *sstream = SOUP_OUTPUT_STREAM (stream);
+	GSource *base_source, *pollable_source;
+
+	base_source = g_pollable_output_stream_create_source (G_POLLABLE_OUTPUT_STREAM (sstream->priv->base_stream), cancellable);
+	g_source_set_dummy_callback (base_source);
+	pollable_source = g_pollable_source_new (G_OBJECT (stream));
+	g_source_add_child_source (pollable_source, base_source);
+	g_source_unref (base_source);
+
+	return pollable_source;
+}
+
+static gssize
+soup_output_stream_write_nonblocking (GPollableOutputStream  *stream,
+				      const void             *buffer,
+				      gsize                   count,
+				      GError                **error)
+{
+	SoupOutputStream *sstream = SOUP_OUTPUT_STREAM (stream);
+
+	switch (sstream->priv->encoding) {
+	case SOUP_ENCODING_CHUNKED:
+		return soup_output_stream_write_chunked (sstream, buffer, count,
+							 FALSE, NULL, error);
+
+	default:
+		return soup_output_stream_write_raw (sstream, buffer, count,
+						     FALSE, NULL, error);
+	}
+}
+
+static void
+soup_output_stream_class_init (SoupOutputStreamClass *stream_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (stream_class);
+	GOutputStreamClass *output_stream_class = G_OUTPUT_STREAM_CLASS (stream_class);
+
+	g_type_class_add_private (stream_class, sizeof (SoupOutputStreamPrivate));
+
+	object_class->constructed = constructed;
+
+	output_stream_class->write_fn = soup_output_stream_write_fn;
+}
+
+static void
+soup_output_stream_pollable_init (GPollableOutputStreamInterface *pollable_interface,
+				  gpointer interface_data)
+{
+	pollable_interface->is_writable = soup_output_stream_is_writable;
+	pollable_interface->create_source = soup_output_stream_create_source;
+	pollable_interface->write_nonblocking = soup_output_stream_write_nonblocking;
+}
+
+SoupOutputStream *
+soup_output_stream_new (GOutputStream *base_stream)
+{
+	return g_object_new (SOUP_TYPE_OUTPUT_STREAM,
+			     "base-stream", base_stream,
+			     "close-base-stream", FALSE,
+			     NULL);
+}
+
+void
+soup_output_stream_set_encoding (SoupOutputStream *sstream,
+				 SoupEncoding     encoding)
+{
+	sstream->priv->encoding = encoding;
+	if (encoding == SOUP_ENCODING_CHUNKED)
+		sstream->priv->chunked_state = SOUP_OUTPUT_STREAM_STATE_CHUNK_SIZE;
+}
+
+gssize
+soup_output_stream_write (SoupOutputStream      *sstream,
+			  const void            *buffer,
+			  gsize                  count,
+			  gboolean               blocking,
+			  GCancellable          *cancellable,
+			  GError               **error)
+{
+	if (blocking) {
+		return g_output_stream_write (G_OUTPUT_STREAM (sstream),
+					      buffer, count,
+					      cancellable, error);
+	} else {
+		return g_pollable_output_stream_write_nonblocking (
+			G_POLLABLE_OUTPUT_STREAM (sstream),
+			buffer, count, cancellable, error);
+	}
+}
diff --git a/libsoup/soup-output-stream.h b/libsoup/soup-output-stream.h
new file mode 100644
index 0000000..554aef1
--- /dev/null
+++ b/libsoup/soup-output-stream.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ */
+
+#ifndef SOUP_OUTPUT_STREAM_H
+#define SOUP_OUTPUT_STREAM_H 1
+
+#include <libsoup/soup-types.h>
+#include <libsoup/soup-message-headers.h>
+
+G_BEGIN_DECLS
+
+#define SOUP_TYPE_OUTPUT_STREAM            (soup_output_stream_get_type ())
+#define SOUP_OUTPUT_STREAM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUP_TYPE_OUTPUT_STREAM, SoupOutputStream))
+#define SOUP_OUTPUT_STREAM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_OUTPUT_STREAM, SoupOutputStreamClass))
+#define SOUP_IS_OUTPUT_STREAM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SOUP_TYPE_OUTPUT_STREAM))
+#define SOUP_IS_OUTPUT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), SOUP_TYPE_OUTPUT_STREAM))
+#define SOUP_OUTPUT_STREAM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUP_TYPE_OUTPUT_STREAM, SoupOutputStreamClass))
+
+typedef struct _SoupOutputStreamPrivate SoupOutputStreamPrivate;
+
+typedef struct {
+	GFilterOutputStream parent;
+
+	SoupOutputStreamPrivate *priv;
+} SoupOutputStream;
+
+typedef struct {
+	GFilterOutputStreamClass parent_class;
+
+	/* Padding for future expansion */
+	void (*_libsoup_reserved1) (void);
+	void (*_libsoup_reserved2) (void);
+	void (*_libsoup_reserved3) (void);
+	void (*_libsoup_reserved4) (void);
+} SoupOutputStreamClass;
+
+GType soup_output_stream_get_type (void);
+
+SoupOutputStream *soup_output_stream_new          (GOutputStream     *base_stream);
+
+void              soup_output_stream_set_encoding (SoupOutputStream  *sstream,
+						   SoupEncoding       encoding);
+
+gssize            soup_output_stream_write        (SoupOutputStream  *sstream,
+						   const void        *buffer,
+						   gsize              count,
+						   gboolean           blocking,
+						   GCancellable      *cancellable,
+						   GError           **error);
+
+G_END_DECLS
+
+#endif /* SOUP_OUTPUT_STREAM_H */



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