Blame tests/chunk-io-test.c

Packit Service ca3877
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
Packit Service ca3877
/*
Packit Service ca3877
 * Copyright 2013 Red Hat, Inc.
Packit Service ca3877
 */
Packit Service ca3877
Packit Service ca3877
#include "test-utils.h"
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
force_io_streams_init (void)
Packit Service ca3877
{
Packit Service ca3877
	SoupServer *server;
Packit Service ca3877
	SoupSession *session;
Packit Service ca3877
	SoupURI *base_uri;
Packit Service ca3877
	SoupMessage *msg;
Packit Service ca3877
Packit Service ca3877
	/* Poke libsoup enough to cause SoupBodyInputStream and
Packit Service ca3877
	 * SoupBodyOutputStream to get defined, so we can find them
Packit Service ca3877
	 * via g_type_from_name() later.
Packit Service ca3877
	 */
Packit Service ca3877
Packit Service ca3877
	server = soup_test_server_new (TRUE);
Packit Service ca3877
	base_uri = soup_test_server_get_uri (server, "http", NULL);
Packit Service ca3877
Packit Service ca3877
	session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
Packit Service ca3877
	msg = soup_message_new_from_uri ("POST", base_uri);
Packit Service ca3877
	soup_session_send_message (session, msg);
Packit Service ca3877
	g_object_unref (msg);
Packit Service ca3877
	soup_test_session_abort_unref (session);
Packit Service ca3877
Packit Service ca3877
	soup_uri_free (base_uri);
Packit Service ca3877
	soup_test_server_quit_unref (server);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
typedef struct {
Packit Service ca3877
	GFilterInputStream grandparent;
Packit Service ca3877
Packit Service ca3877
	gpointer *soup_filter_input_stream_private;
Packit Service ca3877
Packit Service ca3877
	gboolean is_readable;
Packit Service ca3877
} SlowInputStream;
Packit Service ca3877
Packit Service ca3877
typedef struct {
Packit Service ca3877
	GFilterInputStreamClass grandparent;
Packit Service ca3877
} SlowInputStreamClass;
Packit Service ca3877
Packit Service ca3877
GType slow_input_stream_get_type (void);
Packit Service ca3877
static void slow_pollable_input_stream_init (GPollableInputStreamInterface *pollable_interface,
Packit Service ca3877
					     gpointer interface_data);
Packit Service ca3877
Packit Service ca3877
G_DEFINE_TYPE_WITH_CODE (SlowInputStream, slow_input_stream,
Packit Service ca3877
			 g_type_from_name ("SoupFilterInputStream"),
Packit Service ca3877
			 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM, slow_pollable_input_stream_init);
Packit Service ca3877
			 )
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
slow_input_stream_init (SlowInputStream *sis)
Packit Service ca3877
{
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static gssize
Packit Service ca3877
slow_input_stream_read (GInputStream  *stream,
Packit Service ca3877
			void          *buffer,
Packit Service ca3877
			gsize          count,
Packit Service ca3877
			GCancellable  *cancellable,
Packit Service ca3877
			GError       **error)
Packit Service ca3877
{
Packit Service ca3877
	return g_input_stream_read (G_FILTER_INPUT_STREAM (stream)->base_stream,
Packit Service ca3877
				    buffer, 1, cancellable, error);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
slow_input_stream_class_init (SlowInputStreamClass *sisclass)
Packit Service ca3877
{
Packit Service ca3877
	GInputStreamClass *input_stream_class = G_INPUT_STREAM_CLASS (sisclass);
Packit Service ca3877
Packit Service ca3877
	input_stream_class->read_fn = slow_input_stream_read;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static gboolean
Packit Service ca3877
slow_input_stream_is_readable (GPollableInputStream *stream)
Packit Service ca3877
{
Packit Service ca3877
	return ((SlowInputStream *)stream)->is_readable;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static gssize
Packit Service ca3877
slow_input_stream_read_nonblocking (GPollableInputStream  *stream,
Packit Service ca3877
				    void                  *buffer,
Packit Service ca3877
				    gsize                  count,
Packit Service ca3877
				    GError               **error)
Packit Service ca3877
{
Packit Service ca3877
	if (((SlowInputStream *)stream)->is_readable) {
Packit Service ca3877
		((SlowInputStream *)stream)->is_readable = FALSE;
Packit Service ca3877
		return slow_input_stream_read (G_INPUT_STREAM (stream), buffer, count,
Packit Service ca3877
					       NULL, error);
Packit Service ca3877
	} else {
Packit Service ca3877
		g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
Packit Service ca3877
				     "would block");
Packit Service ca3877
		return -1;
Packit Service ca3877
	}
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static GSource *
Packit Service ca3877
slow_input_stream_create_source (GPollableInputStream *stream,
Packit Service ca3877
				 GCancellable *cancellable)
Packit Service ca3877
{
Packit Service ca3877
	GSource *base_source, *pollable_source;
Packit Service ca3877
Packit Service ca3877
	((SlowInputStream *)stream)->is_readable = TRUE;
Packit Service ca3877
	base_source = g_timeout_source_new (0);
Packit Service ca3877
	g_source_set_dummy_callback (base_source);
Packit Service ca3877
Packit Service ca3877
	pollable_source = g_pollable_source_new (G_OBJECT (stream));
Packit Service ca3877
	g_source_add_child_source (pollable_source, base_source);
Packit Service ca3877
	g_source_unref (base_source);
Packit Service ca3877
Packit Service ca3877
	return pollable_source;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
slow_pollable_input_stream_init (GPollableInputStreamInterface *pollable_interface,
Packit Service ca3877
				 gpointer interface_data)
Packit Service ca3877
{
Packit Service ca3877
	pollable_interface->is_readable = slow_input_stream_is_readable;
Packit Service ca3877
	pollable_interface->read_nonblocking = slow_input_stream_read_nonblocking;
Packit Service ca3877
	pollable_interface->create_source = slow_input_stream_create_source;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
typedef struct {
Packit Service ca3877
	GFilterOutputStream parent;
Packit Service ca3877
Packit Service ca3877
	gboolean is_writable;
Packit Service ca3877
} SlowOutputStream;
Packit Service ca3877
Packit Service ca3877
typedef struct {
Packit Service ca3877
	GFilterOutputStreamClass parent;
Packit Service ca3877
} SlowOutputStreamClass;
Packit Service ca3877
Packit Service ca3877
GType slow_output_stream_get_type (void);
Packit Service ca3877
Packit Service ca3877
static void slow_pollable_output_stream_init (GPollableOutputStreamInterface *pollable_interface,
Packit Service ca3877
					      gpointer interface_data);
Packit Service ca3877
Packit Service ca3877
G_DEFINE_TYPE_WITH_CODE (SlowOutputStream, slow_output_stream,
Packit Service ca3877
			 g_type_from_name ("GFilterOutputStream"),
Packit Service ca3877
			 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM, slow_pollable_output_stream_init);
Packit Service ca3877
			 )
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
slow_output_stream_init (SlowOutputStream *sis)
Packit Service ca3877
{
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static gssize
Packit Service ca3877
slow_output_stream_write (GOutputStream  *stream,
Packit Service ca3877
			  const void     *buffer,
Packit Service ca3877
			  gsize           count,
Packit Service ca3877
			  GCancellable   *cancellable,
Packit Service ca3877
			  GError        **error)
Packit Service ca3877
{
Packit Service ca3877
	return g_output_stream_write (G_FILTER_OUTPUT_STREAM (stream)->base_stream,
Packit Service ca3877
				      buffer, 1, cancellable, error);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
slow_output_stream_class_init (SlowOutputStreamClass *sisclass)
Packit Service ca3877
{
Packit Service ca3877
	GOutputStreamClass *output_stream_class = G_OUTPUT_STREAM_CLASS (sisclass);
Packit Service ca3877
Packit Service ca3877
	output_stream_class->write_fn = slow_output_stream_write;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static gboolean
Packit Service ca3877
slow_output_stream_is_writable (GPollableOutputStream *stream)
Packit Service ca3877
{
Packit Service ca3877
	return ((SlowOutputStream *)stream)->is_writable;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static gssize
Packit Service ca3877
slow_output_stream_write_nonblocking (GPollableOutputStream  *stream,
Packit Service ca3877
				      const void             *buffer,
Packit Service ca3877
				      gsize                   count,
Packit Service ca3877
				      GError                **error)
Packit Service ca3877
{
Packit Service ca3877
	if (((SlowOutputStream *)stream)->is_writable) {
Packit Service ca3877
		((SlowOutputStream *)stream)->is_writable = FALSE;
Packit Service ca3877
		return slow_output_stream_write (G_OUTPUT_STREAM (stream), buffer, count,
Packit Service ca3877
						 NULL, error);
Packit Service ca3877
	} else {
Packit Service ca3877
		g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
Packit Service ca3877
				     "would block");
Packit Service ca3877
		return -1;
Packit Service ca3877
	}
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static GSource *
Packit Service ca3877
slow_output_stream_create_source (GPollableOutputStream *stream,
Packit Service ca3877
				  GCancellable *cancellable)
Packit Service ca3877
{
Packit Service ca3877
	GSource *base_source, *pollable_source;
Packit Service ca3877
Packit Service ca3877
	((SlowOutputStream *)stream)->is_writable = TRUE;
Packit Service ca3877
	base_source = g_timeout_source_new (0);
Packit Service ca3877
	g_source_set_dummy_callback (base_source);
Packit Service ca3877
Packit Service ca3877
	pollable_source = g_pollable_source_new (G_OBJECT (stream));
Packit Service ca3877
	g_source_add_child_source (pollable_source, base_source);
Packit Service ca3877
	g_source_unref (base_source);
Packit Service ca3877
Packit Service ca3877
	return pollable_source;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
slow_pollable_output_stream_init (GPollableOutputStreamInterface *pollable_interface,
Packit Service ca3877
				  gpointer interface_data)
Packit Service ca3877
{
Packit Service ca3877
	pollable_interface->is_writable = slow_output_stream_is_writable;
Packit Service ca3877
	pollable_interface->write_nonblocking = slow_output_stream_write_nonblocking;
Packit Service ca3877
	pollable_interface->create_source = slow_output_stream_create_source;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
typedef struct {
Packit Service ca3877
	GFilterOutputStream parent;
Packit Service ca3877
Packit Service ca3877
	gboolean is_broken;
Packit Service ca3877
} BreakingOutputStream;
Packit Service ca3877
Packit Service ca3877
typedef struct {
Packit Service ca3877
	GFilterOutputStreamClass parent;
Packit Service ca3877
} BreakingOutputStreamClass;
Packit Service ca3877
Packit Service ca3877
GType breaking_output_stream_get_type (void);
Packit Service ca3877
Packit Service ca3877
static void breaking_pollable_output_stream_init (GPollableOutputStreamInterface *pollable_interface,
Packit Service ca3877
						  gpointer interface_data);
Packit Service ca3877
Packit Service ca3877
G_DEFINE_TYPE_WITH_CODE (BreakingOutputStream, breaking_output_stream,
Packit Service ca3877
			 g_type_from_name ("GFilterOutputStream"),
Packit Service ca3877
			 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM, breaking_pollable_output_stream_init);
Packit Service ca3877
			 )
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
breaking_output_stream_init (BreakingOutputStream *sis)
Packit Service ca3877
{
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static gssize
Packit Service ca3877
breaking_output_stream_write (GOutputStream  *stream,
Packit Service ca3877
			      const void     *buffer,
Packit Service ca3877
			      gsize           count,
Packit Service ca3877
			      GCancellable   *cancellable,
Packit Service ca3877
			      GError        **error)
Packit Service ca3877
{
Packit Service ca3877
	if (((BreakingOutputStream *)stream)->is_broken) {
Packit Service ca3877
		g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "failed");
Packit Service ca3877
		return -1;
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	if (count > 128) {
Packit Service ca3877
		((BreakingOutputStream *)stream)->is_broken = TRUE;
Packit Service ca3877
		count /= 2;
Packit Service ca3877
	}
Packit Service ca3877
	return g_output_stream_write (G_FILTER_OUTPUT_STREAM (stream)->base_stream,
Packit Service ca3877
				      buffer, count, cancellable, error);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
breaking_output_stream_class_init (BreakingOutputStreamClass *sisclass)
Packit Service ca3877
{
Packit Service ca3877
	GOutputStreamClass *output_stream_class = G_OUTPUT_STREAM_CLASS (sisclass);
Packit Service ca3877
Packit Service ca3877
	output_stream_class->write_fn = breaking_output_stream_write;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static gboolean
Packit Service ca3877
breaking_output_stream_is_writable (GPollableOutputStream *stream)
Packit Service ca3877
{
Packit Service ca3877
	return TRUE;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static gssize
Packit Service ca3877
breaking_output_stream_write_nonblocking (GPollableOutputStream  *stream,
Packit Service ca3877
					  const void             *buffer,
Packit Service ca3877
					  gsize                   count,
Packit Service ca3877
					  GError                **error)
Packit Service ca3877
{
Packit Service ca3877
	if (((BreakingOutputStream *)stream)->is_broken) {
Packit Service ca3877
		g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "failed");
Packit Service ca3877
		return -1;
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	if (count > 128) {
Packit Service ca3877
		((BreakingOutputStream *)stream)->is_broken = TRUE;
Packit Service ca3877
		count /= 2;
Packit Service ca3877
	}
Packit Service ca3877
	return g_pollable_output_stream_write_nonblocking (G_POLLABLE_OUTPUT_STREAM (G_FILTER_OUTPUT_STREAM (stream)->base_stream),
Packit Service ca3877
							   buffer, count, NULL, error);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static GSource *
Packit Service ca3877
breaking_output_stream_create_source (GPollableOutputStream *stream,
Packit Service ca3877
				      GCancellable *cancellable)
Packit Service ca3877
{
Packit Service ca3877
	GSource *base_source, *pollable_source;
Packit Service ca3877
Packit Service ca3877
	base_source = g_timeout_source_new (0);
Packit Service ca3877
	g_source_set_dummy_callback (base_source);
Packit Service ca3877
Packit Service ca3877
	pollable_source = g_pollable_source_new (G_OBJECT (stream));
Packit Service ca3877
	g_source_add_child_source (pollable_source, base_source);
Packit Service ca3877
	g_source_unref (base_source);
Packit Service ca3877
Packit Service ca3877
	return pollable_source;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
breaking_pollable_output_stream_init (GPollableOutputStreamInterface *pollable_interface,
Packit Service ca3877
				  gpointer interface_data)
Packit Service ca3877
{
Packit Service ca3877
	pollable_interface->is_writable = breaking_output_stream_is_writable;
Packit Service ca3877
	pollable_interface->write_nonblocking = breaking_output_stream_write_nonblocking;
Packit Service ca3877
	pollable_interface->create_source = breaking_output_stream_create_source;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
#define CHUNK_SIZE 1024
Packit Service ca3877
Packit Service ca3877
static GString *
Packit Service ca3877
chunkify (const char *str, gsize length)
Packit Service ca3877
{
Packit Service ca3877
	GString *gstr;
Packit Service ca3877
	int i, size;
Packit Service ca3877
Packit Service ca3877
	gstr = g_string_new (NULL);
Packit Service ca3877
	for (i = 0; i < length; i += CHUNK_SIZE) {
Packit Service ca3877
		size = MIN (CHUNK_SIZE, length - i);
Packit Service ca3877
		g_string_append_printf (gstr, "%x\r\n", size);
Packit Service ca3877
		g_string_append_len (gstr, str + i, size);
Packit Service ca3877
		g_string_append (gstr, "\r\n");
Packit Service ca3877
	}
Packit Service ca3877
	g_string_append (gstr, "0\r\n\r\n");
Packit Service ca3877
Packit Service ca3877
	return gstr;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
do_io_tests (void)
Packit Service ca3877
{
Packit Service ca3877
	GInputStream *imem, *islow, *in;
Packit Service ca3877
	GOutputStream *omem, *oslow, *out;
Packit Service ca3877
	GMemoryOutputStream *mem;
Packit Service ca3877
	SoupBuffer *raw_contents;
Packit Service ca3877
	char *buf;
Packit Service ca3877
	GString *chunkified;
Packit Service ca3877
	GError *error = NULL;
Packit Service ca3877
	gssize nread, nwrote, total;
Packit Service ca3877
	gssize chunk_length, chunk_total;
Packit Service ca3877
Packit Service ca3877
	raw_contents = soup_test_get_index ();
Packit Service ca3877
	chunkified = chunkify (raw_contents->data, raw_contents->length);
Packit Service ca3877
Packit Service ca3877
	debug_printf (1, "  sync read\n");
Packit Service ca3877
Packit Service ca3877
	imem = g_memory_input_stream_new_from_data (chunkified->str, chunkified->len, NULL);
Packit Service ca3877
	islow = g_object_new (slow_input_stream_get_type (),
Packit Service ca3877
			      "base-stream", imem,
Packit Service ca3877
			      "close-base-stream", TRUE,
Packit Service ca3877
			      NULL);
Packit Service ca3877
	in = g_object_new (g_type_from_name ("SoupBodyInputStream"),
Packit Service ca3877
			   "base-stream", islow,
Packit Service ca3877
			   "close-base-stream", TRUE,
Packit Service ca3877
			   "encoding", SOUP_ENCODING_CHUNKED,
Packit Service ca3877
			   NULL);
Packit Service ca3877
	g_object_unref (imem);
Packit Service ca3877
	g_object_unref (islow);
Packit Service ca3877
Packit Service ca3877
	buf = g_malloc (raw_contents->length);
Packit Service ca3877
	total = 0;
Packit Service ca3877
	while (TRUE) {
Packit Service ca3877
		nread = g_input_stream_read (in, buf + total,
Packit Service ca3877
					     raw_contents->length - total,
Packit Service ca3877
					     NULL, &error);
Packit Service ca3877
		g_assert_no_error (error);
Packit Service ca3877
		g_clear_error (&error);
Packit Service ca3877
		if (nread > 0)
Packit Service ca3877
			total += nread;
Packit Service ca3877
		else
Packit Service ca3877
			break;
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	g_input_stream_close (in, NULL, &error);
Packit Service ca3877
	g_assert_no_error (error);
Packit Service ca3877
	g_clear_error (&error);
Packit Service ca3877
	g_object_unref (in);
Packit Service ca3877
Packit Service ca3877
	soup_assert_cmpmem (buf, total, raw_contents->data, raw_contents->length);
Packit Service ca3877
	g_free (buf);
Packit Service ca3877
Packit Service ca3877
	debug_printf (1, "  async read\n");
Packit Service ca3877
Packit Service ca3877
	imem = g_memory_input_stream_new_from_data (chunkified->str, chunkified->len, NULL);
Packit Service ca3877
	islow = g_object_new (slow_input_stream_get_type (),
Packit Service ca3877
			      "base-stream", imem,
Packit Service ca3877
			      "close-base-stream", TRUE,
Packit Service ca3877
			      NULL);
Packit Service ca3877
	in = g_object_new (g_type_from_name ("SoupBodyInputStream"),
Packit Service ca3877
			   "base-stream", islow,
Packit Service ca3877
			   "close-base-stream", TRUE,
Packit Service ca3877
			   "encoding", SOUP_ENCODING_CHUNKED,
Packit Service ca3877
			   NULL);
Packit Service ca3877
	g_object_unref (imem);
Packit Service ca3877
	g_object_unref (islow);
Packit Service ca3877
Packit Service ca3877
	buf = g_malloc (raw_contents->length);
Packit Service ca3877
	total = 0;
Packit Service ca3877
	while (TRUE) {
Packit Service ca3877
		nread = g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM (in),
Packit Service ca3877
								  buf + total,
Packit Service ca3877
								  raw_contents->length - total,
Packit Service ca3877
								  NULL, &error);
Packit Service ca3877
		if (nread == -1 && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
Packit Service ca3877
			GSource *source;
Packit Service ca3877
Packit Service ca3877
			g_clear_error (&error);
Packit Service ca3877
			source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (in), NULL);
Packit Service ca3877
			g_source_set_dummy_callback (source);
Packit Service ca3877
			g_source_attach (source, NULL);
Packit Service ca3877
			while (!g_pollable_input_stream_is_readable (G_POLLABLE_INPUT_STREAM (in)))
Packit Service ca3877
				g_main_context_iteration (NULL, TRUE);
Packit Service ca3877
			g_source_destroy (source);
Packit Service ca3877
			g_source_unref (source);
Packit Service ca3877
			continue;
Packit Service ca3877
		} else if (nread == -1) {
Packit Service ca3877
			g_assert_no_error (error);
Packit Service ca3877
			g_clear_error (&error);
Packit Service ca3877
			break;
Packit Service ca3877
		} else if (nread == 0)
Packit Service ca3877
			break;
Packit Service ca3877
		else
Packit Service ca3877
			total += nread;
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	g_input_stream_close (in, NULL, &error);
Packit Service ca3877
	g_assert_no_error (error);
Packit Service ca3877
	g_clear_error (&error);
Packit Service ca3877
	g_object_unref (in);
Packit Service ca3877
Packit Service ca3877
	soup_assert_cmpmem (buf, total, raw_contents->data, raw_contents->length);
Packit Service ca3877
	g_free (buf);
Packit Service ca3877
Packit Service ca3877
	debug_printf (1, "  sync write\n");
Packit Service ca3877
Packit Service ca3877
	buf = g_malloc (chunkified->len);
Packit Service ca3877
	omem = g_memory_output_stream_new (buf, chunkified->len, NULL, NULL);
Packit Service ca3877
	oslow = g_object_new (slow_output_stream_get_type (),
Packit Service ca3877
			      "base-stream", omem,
Packit Service ca3877
			      "close-base-stream", TRUE,
Packit Service ca3877
			      NULL);
Packit Service ca3877
	out = g_object_new (g_type_from_name ("SoupBodyOutputStream"),
Packit Service ca3877
			    "base-stream", oslow,
Packit Service ca3877
			    "close-base-stream", TRUE,
Packit Service ca3877
			    "encoding", SOUP_ENCODING_CHUNKED,
Packit Service ca3877
			    NULL);
Packit Service ca3877
	g_object_unref (omem);
Packit Service ca3877
	g_object_unref (oslow);
Packit Service ca3877
Packit Service ca3877
	total = chunk_length = chunk_total = 0;
Packit Service ca3877
	while (total < raw_contents->length) {
Packit Service ca3877
		if (chunk_total == chunk_length) {
Packit Service ca3877
			chunk_length = MIN (CHUNK_SIZE, raw_contents->length - total);
Packit Service ca3877
			chunk_total = 0;
Packit Service ca3877
		}
Packit Service ca3877
		nwrote = g_output_stream_write (out, raw_contents->data + total,
Packit Service ca3877
						chunk_length - chunk_total, NULL, &error);
Packit Service ca3877
		g_assert_no_error (error);
Packit Service ca3877
		g_clear_error (&error);
Packit Service ca3877
		if (nwrote > 0) {
Packit Service ca3877
			total += nwrote;
Packit Service ca3877
			chunk_total += nwrote;
Packit Service ca3877
		} else
Packit Service ca3877
			break;
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	g_output_stream_close (out, NULL, &error);
Packit Service ca3877
	g_assert_no_error (error);
Packit Service ca3877
	g_clear_error (&error);
Packit Service ca3877
Packit Service ca3877
	mem = G_MEMORY_OUTPUT_STREAM (omem);
Packit Service ca3877
	soup_assert_cmpmem (g_memory_output_stream_get_data (mem),
Packit Service ca3877
			    g_memory_output_stream_get_data_size (mem),
Packit Service ca3877
			    chunkified->str, chunkified->len);
Packit Service ca3877
Packit Service ca3877
	g_object_unref (out);
Packit Service ca3877
	g_free (buf);
Packit Service ca3877
Packit Service ca3877
	debug_printf (1, "  async write\n");
Packit Service ca3877
Packit Service ca3877
	buf = g_malloc (chunkified->len);
Packit Service ca3877
	omem = g_memory_output_stream_new (buf, chunkified->len, NULL, NULL);
Packit Service ca3877
	oslow = g_object_new (slow_output_stream_get_type (),
Packit Service ca3877
			      "base-stream", omem,
Packit Service ca3877
			      "close-base-stream", TRUE,
Packit Service ca3877
			      NULL);
Packit Service ca3877
	out = g_object_new (g_type_from_name ("SoupBodyOutputStream"),
Packit Service ca3877
			    "base-stream", oslow,
Packit Service ca3877
			    "close-base-stream", TRUE,
Packit Service ca3877
			    "encoding", SOUP_ENCODING_CHUNKED,
Packit Service ca3877
			    NULL);
Packit Service ca3877
	g_object_unref (omem);
Packit Service ca3877
	g_object_unref (oslow);
Packit Service ca3877
Packit Service ca3877
	total = chunk_length = chunk_total = 0;
Packit Service ca3877
	while (total < raw_contents->length) {
Packit Service ca3877
		if (chunk_total == chunk_length) {
Packit Service ca3877
			chunk_length = MIN (CHUNK_SIZE, raw_contents->length - total);
Packit Service ca3877
			chunk_total = 0;
Packit Service ca3877
		}
Packit Service ca3877
		nwrote = g_pollable_output_stream_write_nonblocking (G_POLLABLE_OUTPUT_STREAM (out),
Packit Service ca3877
								     raw_contents->data + total,
Packit Service ca3877
								     chunk_length - chunk_total,
Packit Service ca3877
								     NULL, &error);
Packit Service ca3877
		if (nwrote == -1 && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
Packit Service ca3877
			GSource *source;
Packit Service ca3877
Packit Service ca3877
			g_clear_error (&error);
Packit Service ca3877
			source = g_pollable_output_stream_create_source (G_POLLABLE_OUTPUT_STREAM (out), NULL);
Packit Service ca3877
			g_source_set_dummy_callback (source);
Packit Service ca3877
			g_source_attach (source, NULL);
Packit Service ca3877
			while (!g_pollable_output_stream_is_writable (G_POLLABLE_OUTPUT_STREAM (out)))
Packit Service ca3877
				g_main_context_iteration (NULL, TRUE);
Packit Service ca3877
			g_source_destroy (source);
Packit Service ca3877
			g_source_unref (source);
Packit Service ca3877
			continue;
Packit Service ca3877
		} else if (nwrote == -1) {
Packit Service ca3877
			g_assert_no_error (error);
Packit Service ca3877
			g_clear_error (&error);
Packit Service ca3877
			break;
Packit Service ca3877
		} else {
Packit Service ca3877
			total += nwrote;
Packit Service ca3877
			chunk_total += nwrote;
Packit Service ca3877
		}
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	g_output_stream_close (out, NULL, &error);
Packit Service ca3877
	g_assert_no_error (error);
Packit Service ca3877
	g_clear_error (&error);
Packit Service ca3877
Packit Service ca3877
	mem = G_MEMORY_OUTPUT_STREAM (omem);
Packit Service ca3877
	soup_assert_cmpmem (g_memory_output_stream_get_data (mem),
Packit Service ca3877
			    g_memory_output_stream_get_data_size (mem),
Packit Service ca3877
			    chunkified->str, chunkified->len);
Packit Service ca3877
Packit Service ca3877
	g_object_unref (out);
Packit Service ca3877
	g_free (buf);
Packit Service ca3877
Packit Service ca3877
	debug_printf (1, "  failed write\n");
Packit Service ca3877
	/* this succeeds if it doesn't critical */
Packit Service ca3877
Packit Service ca3877
	buf = g_malloc (chunkified->len);
Packit Service ca3877
	omem = g_memory_output_stream_new (buf, chunkified->len, NULL, NULL);
Packit Service ca3877
	oslow = g_object_new (breaking_output_stream_get_type (),
Packit Service ca3877
			      "base-stream", omem,
Packit Service ca3877
			      "close-base-stream", TRUE,
Packit Service ca3877
			      NULL);
Packit Service ca3877
	out = g_object_new (g_type_from_name ("SoupBodyOutputStream"),
Packit Service ca3877
			    "base-stream", oslow,
Packit Service ca3877
			    "close-base-stream", TRUE,
Packit Service ca3877
			    "encoding", SOUP_ENCODING_CHUNKED,
Packit Service ca3877
			    NULL);
Packit Service ca3877
	g_object_unref (omem);
Packit Service ca3877
	g_object_unref (oslow);
Packit Service ca3877
Packit Service ca3877
	total = 0;
Packit Service ca3877
	while (total < raw_contents->length) {
Packit Service ca3877
		nwrote = g_output_stream_write (out, raw_contents->data + total,
Packit Service ca3877
						raw_contents->length - total, NULL, NULL);
Packit Service ca3877
		if (nwrote == -1)
Packit Service ca3877
			break;
Packit Service ca3877
		else
Packit Service ca3877
			total += nwrote;
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	g_assert_cmpint (total, !=, raw_contents->length);
Packit Service ca3877
Packit Service ca3877
	g_output_stream_close (out, NULL, NULL);
Packit Service ca3877
	g_object_unref (out);
Packit Service ca3877
Packit Service ca3877
	g_free (buf);
Packit Service ca3877
Packit Service ca3877
	g_string_free (chunkified, TRUE);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
int
Packit Service ca3877
main (int argc, char **argv)
Packit Service ca3877
{
Packit Service ca3877
	int ret;
Packit Service ca3877
Packit Service ca3877
	test_init (argc, argv, NULL);
Packit Service ca3877
Packit Service ca3877
	force_io_streams_init ();
Packit Service ca3877
Packit Service ca3877
	g_test_add_func ("/chunk-io", do_io_tests);
Packit Service ca3877
Packit Service ca3877
	ret = g_test_run ();
Packit Service ca3877
Packit Service ca3877
	test_cleanup ();
Packit Service ca3877
	return ret;
Packit Service ca3877
}