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.
14 #include "soup-client-input-stream.h"
15 #include "soup-marshal.h"
16 #include "soup-message.h"
17 #include "soup-message-private.h"
19 struct _SoupClientInputStreamPrivate {
28 static guint signals[LAST_SIGNAL] = { 0 };
36 static GPollableInputStreamInterface *soup_client_input_stream_parent_pollable_interface;
37 static void soup_client_input_stream_pollable_init (GPollableInputStreamInterface *pollable_interface, gpointer interface_data);
39 G_DEFINE_TYPE_WITH_CODE (SoupClientInputStream, soup_client_input_stream, SOUP_TYPE_FILTER_INPUT_STREAM,
40 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM,
41 soup_client_input_stream_pollable_init))
44 soup_client_input_stream_init (SoupClientInputStream *stream)
46 stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
47 SOUP_TYPE_CLIENT_INPUT_STREAM,
48 SoupClientInputStreamPrivate);
52 set_property (GObject *object, guint prop_id,
53 const GValue *value, GParamSpec *pspec)
55 SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (object);
59 cistream->priv->msg = g_value_dup_object (value);
62 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
68 get_property (GObject *object, guint prop_id,
69 GValue *value, GParamSpec *pspec)
71 SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (object);
75 g_value_set_object (value, cistream->priv->msg);
78 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
83 /* Temporary HACK to keep SoupCache working. See soup_client_input_stream_read_fn()
84 * and soup_client_input_stream_read_nonblocking().
87 soup_client_input_stream_emit_got_chunk (SoupClientInputStream *stream, void *data, gssize nread)
89 SoupBuffer *buffer = soup_buffer_new (SOUP_MEMORY_TEMPORARY, data, nread);
90 soup_message_got_chunk (stream->priv->msg, buffer);
91 soup_buffer_free (buffer);
95 soup_client_input_stream_read_fn (GInputStream *stream,
98 GCancellable *cancellable,
103 nread = G_INPUT_STREAM_CLASS (soup_client_input_stream_parent_class)->
104 read_fn (stream, buffer, count, cancellable, error);
107 g_signal_emit (stream, signals[EOF], 0);
109 /* Temporary HACK to keep SoupCache working */
111 soup_client_input_stream_emit_got_chunk (SOUP_CLIENT_INPUT_STREAM (stream),
119 soup_client_input_stream_read_nonblocking (GPollableInputStream *stream,
126 nread = soup_client_input_stream_parent_pollable_interface->
127 read_nonblocking (stream, buffer, count, error);
130 g_signal_emit (stream, signals[EOF], 0);
132 /* Temporary HACK to keep SoupCache working */
134 soup_client_input_stream_emit_got_chunk (SOUP_CLIENT_INPUT_STREAM (stream),
142 soup_client_input_stream_close_fn (GInputStream *stream,
143 GCancellable *cancellable,
146 SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (stream);
148 if (!soup_message_io_run_until_finish (cistream->priv->msg,
152 return G_INPUT_STREAM_CLASS (soup_client_input_stream_parent_class)->close_fn (stream, cancellable, error);
156 SoupClientInputStream *cistream;
158 GCancellable *cancellable;
159 GSimpleAsyncResult *result;
163 close_async_data_free (CloseAsyncData *cad)
165 if (cad->cancellable)
166 g_object_unref (cad->cancellable);
167 g_object_unref (cad->result);
168 g_slice_free (CloseAsyncData, cad);
172 base_stream_closed (GObject *source, GAsyncResult *result, gpointer user_data)
174 CloseAsyncData *cad = user_data;
175 GError *error = NULL;
177 if (G_INPUT_STREAM_CLASS (soup_client_input_stream_parent_class)->
178 close_finish (G_INPUT_STREAM (cad->cistream), result, &error))
179 g_simple_async_result_set_op_res_gboolean (cad->result, TRUE);
181 g_simple_async_result_take_error (cad->result, error);
183 g_simple_async_result_complete_in_idle (cad->result);
184 close_async_data_free (cad);
188 close_async_ready (SoupMessage *msg, gpointer user_data)
190 CloseAsyncData *cad = user_data;
191 GError *error = NULL;
193 if (soup_message_io_run_until_finish (cad->cistream->priv->msg,
194 cad->cancellable, &error)) {
195 G_INPUT_STREAM_CLASS (soup_client_input_stream_parent_class)->
196 close_async (G_INPUT_STREAM (cad->cistream),
202 } else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
203 g_simple_async_result_take_error (cad->result, error);
204 g_simple_async_result_complete_in_idle (cad->result);
205 close_async_data_free (cad);
213 soup_client_input_stream_close_async (GInputStream *stream,
215 GCancellable *cancellable,
216 GAsyncReadyCallback callback,
222 cad = g_slice_new (CloseAsyncData);
223 cad->cistream = SOUP_CLIENT_INPUT_STREAM (stream);
224 cad->result = g_simple_async_result_new (G_OBJECT (stream),
226 soup_client_input_stream_close_async);
227 cad->priority = priority;
228 cad->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
230 source = soup_message_io_get_source (cad->cistream->priv->msg,
232 close_async_ready, cad);
233 g_source_set_priority (source, priority);
234 g_source_attach (source, g_main_context_get_thread_default ());
235 g_source_unref (source);
239 soup_client_input_stream_close_finish (GInputStream *stream,
240 GAsyncResult *result,
243 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
245 if (g_simple_async_result_propagate_error (simple, error))
248 return g_simple_async_result_get_op_res_gboolean (simple);
252 soup_client_input_stream_class_init (SoupClientInputStreamClass *stream_class)
254 GObjectClass *object_class = G_OBJECT_CLASS (stream_class);
255 GInputStreamClass *input_stream_class = G_INPUT_STREAM_CLASS (stream_class);
257 g_type_class_add_private (stream_class, sizeof (SoupClientInputStreamPrivate));
259 object_class->set_property = set_property;
260 object_class->get_property = get_property;
262 input_stream_class->read_fn = soup_client_input_stream_read_fn;
263 input_stream_class->close_fn = soup_client_input_stream_close_fn;
264 input_stream_class->close_async = soup_client_input_stream_close_async;
265 input_stream_class->close_finish = soup_client_input_stream_close_finish;
269 G_OBJECT_CLASS_TYPE (object_class),
273 _soup_marshal_NONE__NONE,
276 g_object_class_install_property (
277 object_class, PROP_MESSAGE,
278 g_param_spec_object ("message",
282 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
286 soup_client_input_stream_pollable_init (GPollableInputStreamInterface *pollable_interface,
287 gpointer interface_data)
289 soup_client_input_stream_parent_pollable_interface =
290 g_type_interface_peek_parent (pollable_interface);
292 pollable_interface->read_nonblocking = soup_client_input_stream_read_nonblocking;
296 soup_client_input_stream_new (GInputStream *base_stream,
299 return g_object_new (SOUP_TYPE_CLIENT_INPUT_STREAM,
300 "base-stream", base_stream,