1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-client-input-stream.c
5 * Copyright 2010-2012 Red Hat, Inc.
12 #include "soup-client-input-stream.h"
14 #include "soup-marshal.h"
15 #include "soup-message-private.h"
17 struct _SoupClientInputStreamPrivate {
26 static guint signals[LAST_SIGNAL] = { 0 };
34 static GPollableInputStreamInterface *soup_client_input_stream_parent_pollable_interface;
35 static void soup_client_input_stream_pollable_init (GPollableInputStreamInterface *pollable_interface, gpointer interface_data);
37 G_DEFINE_TYPE_WITH_CODE (SoupClientInputStream, soup_client_input_stream, SOUP_TYPE_FILTER_INPUT_STREAM,
38 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM,
39 soup_client_input_stream_pollable_init))
42 soup_client_input_stream_init (SoupClientInputStream *stream)
44 stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
45 SOUP_TYPE_CLIENT_INPUT_STREAM,
46 SoupClientInputStreamPrivate);
50 soup_client_input_stream_finalize (GObject *object)
52 SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (object);
54 g_clear_object (&cistream->priv->msg);
56 G_OBJECT_CLASS (soup_client_input_stream_parent_class)->finalize (object);
60 soup_client_input_stream_set_property (GObject *object, guint prop_id,
61 const GValue *value, GParamSpec *pspec)
63 SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (object);
67 cistream->priv->msg = g_value_dup_object (value);
70 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
76 soup_client_input_stream_get_property (GObject *object, guint prop_id,
77 GValue *value, GParamSpec *pspec)
79 SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (object);
83 g_value_set_object (value, cistream->priv->msg);
86 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
92 soup_client_input_stream_read_fn (GInputStream *stream,
95 GCancellable *cancellable,
100 nread = G_INPUT_STREAM_CLASS (soup_client_input_stream_parent_class)->
101 read_fn (stream, buffer, count, cancellable, error);
104 g_signal_emit (stream, signals[EOF], 0);
110 soup_client_input_stream_read_nonblocking (GPollableInputStream *stream,
117 nread = soup_client_input_stream_parent_pollable_interface->
118 read_nonblocking (stream, buffer, count, error);
121 g_signal_emit (stream, signals[EOF], 0);
127 soup_client_input_stream_close_fn (GInputStream *stream,
128 GCancellable *cancellable,
131 SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (stream);
133 return soup_message_io_run_until_finish (cistream->priv->msg,
138 idle_finish_close (gpointer user_data)
140 GTask *task = user_data;
142 g_task_return_boolean (task, TRUE);
143 g_object_unref (task);
148 close_async_ready (SoupMessage *msg, gpointer user_data)
150 GTask *task = user_data;
151 SoupClientInputStream *cistream = g_task_get_source_object (task);
152 GError *error = NULL;
154 if (!soup_message_io_run_until_finish (cistream->priv->msg,
155 g_task_get_cancellable (task),
157 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
158 g_error_free (error);
163 g_task_return_error (task, error);
164 g_object_unref (task);
168 /* Due to a historical accident, SoupSessionAsync relies on us
169 * waiting one extra cycle after run_until_finish() returns.
170 * Ugh. FIXME later when it's easier to do.
172 soup_add_idle (g_main_context_get_thread_default (),
173 idle_finish_close, task);
178 soup_client_input_stream_close_async (GInputStream *stream,
180 GCancellable *cancellable,
181 GAsyncReadyCallback callback,
184 SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (stream);
188 task = g_task_new (stream, cancellable, callback, user_data);
189 g_task_set_priority (task, priority);
191 source = soup_message_io_get_source (cistream->priv->msg,
192 cancellable, NULL, NULL);
194 g_task_attach_source (task, source, (GSourceFunc) close_async_ready);
195 g_source_unref (source);
199 soup_client_input_stream_close_finish (GInputStream *stream,
200 GAsyncResult *result,
203 return g_task_propagate_boolean (G_TASK (result), error);
207 soup_client_input_stream_class_init (SoupClientInputStreamClass *stream_class)
209 GObjectClass *object_class = G_OBJECT_CLASS (stream_class);
210 GInputStreamClass *input_stream_class = G_INPUT_STREAM_CLASS (stream_class);
212 g_type_class_add_private (stream_class, sizeof (SoupClientInputStreamPrivate));
214 object_class->finalize = soup_client_input_stream_finalize;
215 object_class->set_property = soup_client_input_stream_set_property;
216 object_class->get_property = soup_client_input_stream_get_property;
218 input_stream_class->read_fn = soup_client_input_stream_read_fn;
219 input_stream_class->close_fn = soup_client_input_stream_close_fn;
220 input_stream_class->close_async = soup_client_input_stream_close_async;
221 input_stream_class->close_finish = soup_client_input_stream_close_finish;
225 G_OBJECT_CLASS_TYPE (object_class),
229 _soup_marshal_NONE__NONE,
232 g_object_class_install_property (
233 object_class, PROP_MESSAGE,
234 g_param_spec_object ("message",
238 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
242 soup_client_input_stream_pollable_init (GPollableInputStreamInterface *pollable_interface,
243 gpointer interface_data)
245 soup_client_input_stream_parent_pollable_interface =
246 g_type_interface_peek_parent (pollable_interface);
248 pollable_interface->read_nonblocking = soup_client_input_stream_read_nonblocking;
252 soup_client_input_stream_new (GInputStream *base_stream,
255 return g_object_new (SOUP_TYPE_CLIENT_INPUT_STREAM,
256 "base-stream", base_stream,