Reapplying patch to disable attempts to use gtk-doc
[profile/ivi/libsoup2.4.git] / libsoup / soup-client-input-stream.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-client-input-stream.c
4  *
5  * Copyright 2010-2012 Red Hat, Inc.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include <gio/gio.h>
13
14 #include "soup-client-input-stream.h"
15 #include "soup-marshal.h"
16 #include "soup-message.h"
17 #include "soup-message-private.h"
18
19 struct _SoupClientInputStreamPrivate {
20         SoupMessage  *msg;
21 };
22
23 enum {
24         EOF,
25         LAST_SIGNAL
26 };
27
28 static guint signals[LAST_SIGNAL] = { 0 };
29
30 enum {
31         PROP_0,
32
33         PROP_MESSAGE
34 };
35
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);
38
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))
42
43 static void
44 soup_client_input_stream_init (SoupClientInputStream *stream)
45 {
46         stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
47                                                     SOUP_TYPE_CLIENT_INPUT_STREAM,
48                                                     SoupClientInputStreamPrivate);
49 }
50
51 static void
52 set_property (GObject *object, guint prop_id,
53               const GValue *value, GParamSpec *pspec)
54 {
55         SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (object);
56
57         switch (prop_id) {
58         case PROP_MESSAGE:
59                 cistream->priv->msg = g_value_dup_object (value);
60                 break;
61         default:
62                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
63                 break;
64         }
65 }
66
67 static void
68 get_property (GObject *object, guint prop_id,
69               GValue *value, GParamSpec *pspec)
70 {
71         SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (object);
72
73         switch (prop_id) {
74         case PROP_MESSAGE:
75                 g_value_set_object (value, cistream->priv->msg);
76                 break;
77         default:
78                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
79                 break;
80         }
81 }
82
83 /* Temporary HACK to keep SoupCache working. See soup_client_input_stream_read_fn()
84  * and soup_client_input_stream_read_nonblocking().
85  */
86 static void
87 soup_client_input_stream_emit_got_chunk (SoupClientInputStream *stream, void *data, gssize nread)
88 {
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);
92 }
93
94 static gssize
95 soup_client_input_stream_read_fn (GInputStream  *stream,
96                                   void          *buffer,
97                                   gsize          count,
98                                   GCancellable  *cancellable,
99                                   GError       **error)
100 {
101         gssize nread;
102
103         nread = G_INPUT_STREAM_CLASS (soup_client_input_stream_parent_class)->
104                 read_fn (stream, buffer, count, cancellable, error);
105
106         if (nread == 0)
107                 g_signal_emit (stream, signals[EOF], 0);
108
109         /* Temporary HACK to keep SoupCache working */
110         if (nread > 0) {
111                 soup_client_input_stream_emit_got_chunk (SOUP_CLIENT_INPUT_STREAM (stream),
112                                                          buffer, nread);
113         }
114
115         return nread;
116 }
117
118 static gssize
119 soup_client_input_stream_read_nonblocking (GPollableInputStream  *stream,
120                                            void                  *buffer,
121                                            gsize                  count,
122                                            GError               **error)
123 {
124         gssize nread;
125
126         nread = soup_client_input_stream_parent_pollable_interface->
127                 read_nonblocking (stream, buffer, count, error);
128
129         if (nread == 0)
130                 g_signal_emit (stream, signals[EOF], 0);
131
132         /* Temporary HACK to keep SoupCache working */
133         if (nread > 0) {
134                 soup_client_input_stream_emit_got_chunk (SOUP_CLIENT_INPUT_STREAM (stream),
135                                                          buffer, nread);
136         }
137
138         return nread;
139 }
140
141 static gboolean
142 soup_client_input_stream_close_fn (GInputStream  *stream,
143                                    GCancellable  *cancellable,
144                                    GError       **error)
145 {
146         SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (stream);
147
148         if (!soup_message_io_run_until_finish (cistream->priv->msg,
149                                                cancellable, error))
150                 return FALSE;
151
152         return G_INPUT_STREAM_CLASS (soup_client_input_stream_parent_class)->close_fn (stream, cancellable, error);
153 }
154
155 typedef struct {
156         SoupClientInputStream *cistream;
157         gint priority;
158         GCancellable *cancellable;
159         GSimpleAsyncResult *result;
160 } CloseAsyncData;
161
162 static void
163 close_async_data_free (CloseAsyncData *cad)
164 {
165         if (cad->cancellable)
166                 g_object_unref (cad->cancellable);
167         g_object_unref (cad->result);
168         g_slice_free (CloseAsyncData, cad);
169 }
170
171 static void
172 base_stream_closed (GObject *source, GAsyncResult *result, gpointer user_data)
173 {
174         CloseAsyncData *cad = user_data;
175         GError *error = NULL;
176
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);
180         else
181                 g_simple_async_result_take_error (cad->result, error);
182
183         g_simple_async_result_complete_in_idle (cad->result);
184         close_async_data_free (cad);
185 }
186
187 static gboolean
188 close_async_ready (SoupMessage *msg, gpointer user_data)
189 {
190         CloseAsyncData *cad = user_data;
191         GError *error = NULL;
192
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),
197                                      cad->priority,
198                                      cad->cancellable,
199                                      base_stream_closed,
200                                      cad);
201                 return FALSE;
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);
206                 return FALSE;
207         }
208
209         return TRUE;
210 }
211
212 static void
213 soup_client_input_stream_close_async (GInputStream        *stream,
214                                       gint                 priority,
215                                       GCancellable        *cancellable,
216                                       GAsyncReadyCallback  callback,
217                                       gpointer             user_data)
218 {
219         CloseAsyncData *cad;
220         GSource *source;
221
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),
225                                                  callback, user_data,
226                                                  soup_client_input_stream_close_async);
227         cad->priority = priority;
228         cad->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
229
230         source = soup_message_io_get_source (cad->cistream->priv->msg,
231                                              cancellable,
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);
236 }
237
238 static gboolean
239 soup_client_input_stream_close_finish (GInputStream  *stream,
240                                        GAsyncResult  *result,
241                                        GError       **error)
242 {
243         GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
244
245         if (g_simple_async_result_propagate_error (simple, error))
246                 return FALSE;
247         else
248                 return g_simple_async_result_get_op_res_gboolean (simple);
249 }
250
251 static void
252 soup_client_input_stream_class_init (SoupClientInputStreamClass *stream_class)
253 {
254         GObjectClass *object_class = G_OBJECT_CLASS (stream_class);
255         GInputStreamClass *input_stream_class = G_INPUT_STREAM_CLASS (stream_class);
256
257         g_type_class_add_private (stream_class, sizeof (SoupClientInputStreamPrivate));
258
259         object_class->set_property = set_property;
260         object_class->get_property = get_property;
261
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;
266
267         signals[EOF] =
268                 g_signal_new ("eof",
269                               G_OBJECT_CLASS_TYPE (object_class),
270                               G_SIGNAL_RUN_LAST,
271                               0,
272                               NULL, NULL,
273                               _soup_marshal_NONE__NONE,
274                               G_TYPE_NONE, 0);
275
276         g_object_class_install_property (
277                 object_class, PROP_MESSAGE,
278                 g_param_spec_object ("message",
279                                      "Message",
280                                      "Message",
281                                      SOUP_TYPE_MESSAGE,
282                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
283 }
284
285 static void
286 soup_client_input_stream_pollable_init (GPollableInputStreamInterface *pollable_interface,
287                                         gpointer interface_data)
288 {
289         soup_client_input_stream_parent_pollable_interface =
290                 g_type_interface_peek_parent (pollable_interface);
291
292         pollable_interface->read_nonblocking = soup_client_input_stream_read_nonblocking;
293 }
294
295 GInputStream *
296 soup_client_input_stream_new (GInputStream *base_stream,
297                               SoupMessage  *msg)
298 {
299         return g_object_new (SOUP_TYPE_CLIENT_INPUT_STREAM,
300                              "base-stream", base_stream,
301                              "message", msg,
302                              NULL);
303 }