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-message-private.h"
16 struct _SoupClientInputStreamPrivate {
25 static guint signals[LAST_SIGNAL] = { 0 };
33 static GPollableInputStreamInterface *soup_client_input_stream_parent_pollable_interface;
34 static void soup_client_input_stream_pollable_init (GPollableInputStreamInterface *pollable_interface, gpointer interface_data);
36 G_DEFINE_TYPE_WITH_CODE (SoupClientInputStream, soup_client_input_stream, SOUP_TYPE_FILTER_INPUT_STREAM,
37 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM,
38 soup_client_input_stream_pollable_init))
41 soup_client_input_stream_init (SoupClientInputStream *stream)
43 stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
44 SOUP_TYPE_CLIENT_INPUT_STREAM,
45 SoupClientInputStreamPrivate);
49 soup_client_input_stream_finalize (GObject *object)
51 SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (object);
53 g_clear_object (&cistream->priv->msg);
55 G_OBJECT_CLASS (soup_client_input_stream_parent_class)->finalize (object);
59 soup_client_input_stream_set_property (GObject *object, guint prop_id,
60 const GValue *value, GParamSpec *pspec)
62 SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (object);
66 cistream->priv->msg = g_value_dup_object (value);
69 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
75 soup_client_input_stream_get_property (GObject *object, guint prop_id,
76 GValue *value, GParamSpec *pspec)
78 SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (object);
82 g_value_set_object (value, cistream->priv->msg);
85 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
91 soup_client_input_stream_read_fn (GInputStream *stream,
94 GCancellable *cancellable,
99 nread = G_INPUT_STREAM_CLASS (soup_client_input_stream_parent_class)->
100 read_fn (stream, buffer, count, cancellable, error);
103 g_signal_emit (stream, signals[EOF], 0);
109 soup_client_input_stream_read_nonblocking (GPollableInputStream *stream,
116 nread = soup_client_input_stream_parent_pollable_interface->
117 read_nonblocking (stream, buffer, count, error);
120 g_signal_emit (stream, signals[EOF], 0);
126 soup_client_input_stream_close_fn (GInputStream *stream,
127 GCancellable *cancellable,
130 SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (stream);
133 success = soup_message_io_run_until_finish (cistream->priv->msg, TRUE,
135 soup_message_io_finished (cistream->priv->msg);
140 idle_finish_close (gpointer user_data)
142 GTask *task = user_data;
144 g_task_return_boolean (task, TRUE);
145 g_object_unref (task);
150 close_async_ready (SoupMessage *msg, gpointer user_data)
152 GTask *task = user_data;
153 SoupClientInputStream *cistream = g_task_get_source_object (task);
154 GError *error = NULL;
156 if (!soup_message_io_run_until_finish (cistream->priv->msg, FALSE,
157 g_task_get_cancellable (task),
159 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
160 g_error_free (error);
164 soup_message_io_finished (cistream->priv->msg);
167 g_task_return_error (task, error);
168 g_object_unref (task);
172 /* Due to a historical accident, SoupSessionAsync relies on us
173 * waiting one extra cycle after run_until_finish() returns.
174 * Ugh. FIXME later when it's easier to do.
176 soup_add_idle (g_main_context_get_thread_default (),
177 idle_finish_close, task);
182 soup_client_input_stream_close_async (GInputStream *stream,
184 GCancellable *cancellable,
185 GAsyncReadyCallback callback,
188 SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (stream);
192 task = g_task_new (stream, cancellable, callback, user_data);
193 g_task_set_priority (task, priority);
195 if (close_async_ready (cistream->priv->msg, task) == G_SOURCE_CONTINUE) {
196 source = soup_message_io_get_source (cistream->priv->msg,
197 cancellable, NULL, NULL);
199 g_task_attach_source (task, source, (GSourceFunc) close_async_ready);
200 g_source_unref (source);
205 soup_client_input_stream_close_finish (GInputStream *stream,
206 GAsyncResult *result,
209 return g_task_propagate_boolean (G_TASK (result), error);
213 soup_client_input_stream_class_init (SoupClientInputStreamClass *stream_class)
215 GObjectClass *object_class = G_OBJECT_CLASS (stream_class);
216 GInputStreamClass *input_stream_class = G_INPUT_STREAM_CLASS (stream_class);
218 g_type_class_add_private (stream_class, sizeof (SoupClientInputStreamPrivate));
220 object_class->finalize = soup_client_input_stream_finalize;
221 object_class->set_property = soup_client_input_stream_set_property;
222 object_class->get_property = soup_client_input_stream_get_property;
224 input_stream_class->read_fn = soup_client_input_stream_read_fn;
225 input_stream_class->close_fn = soup_client_input_stream_close_fn;
226 input_stream_class->close_async = soup_client_input_stream_close_async;
227 input_stream_class->close_finish = soup_client_input_stream_close_finish;
231 G_OBJECT_CLASS_TYPE (object_class),
238 g_object_class_install_property (
239 object_class, PROP_MESSAGE,
240 g_param_spec_object ("message",
244 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
248 soup_client_input_stream_pollable_init (GPollableInputStreamInterface *pollable_interface,
249 gpointer interface_data)
251 soup_client_input_stream_parent_pollable_interface =
252 g_type_interface_peek_parent (pollable_interface);
254 pollable_interface->read_nonblocking = soup_client_input_stream_read_nonblocking;
258 soup_client_input_stream_new (GInputStream *base_stream,
261 return g_object_new (SOUP_TYPE_CLIENT_INPUT_STREAM,
262 "base-stream", base_stream,