Remove build warning
[platform/upstream/libsoup.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 "soup-client-input-stream.h"
13 #include "soup.h"
14 #include "soup-message-private.h"
15
16 struct _SoupClientInputStreamPrivate {
17         SoupMessage  *msg;
18 };
19
20 enum {
21         EOF,
22         LAST_SIGNAL
23 };
24
25 static guint signals[LAST_SIGNAL] = { 0 };
26
27 enum {
28         PROP_0,
29
30         PROP_MESSAGE
31 };
32
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);
35
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))
39
40 static void
41 soup_client_input_stream_init (SoupClientInputStream *stream)
42 {
43         stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
44                                                     SOUP_TYPE_CLIENT_INPUT_STREAM,
45                                                     SoupClientInputStreamPrivate);
46 }
47
48 static void
49 soup_client_input_stream_finalize (GObject *object)
50 {
51         SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (object);
52
53         g_clear_object (&cistream->priv->msg);
54
55         G_OBJECT_CLASS (soup_client_input_stream_parent_class)->finalize (object);
56 }
57
58 static void
59 soup_client_input_stream_set_property (GObject *object, guint prop_id,
60                                        const GValue *value, GParamSpec *pspec)
61 {
62         SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (object);
63
64         switch (prop_id) {
65         case PROP_MESSAGE:
66                 cistream->priv->msg = g_value_dup_object (value);
67                 break;
68         default:
69                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
70                 break;
71         }
72 }
73
74 static void
75 soup_client_input_stream_get_property (GObject *object, guint prop_id,
76                                        GValue *value, GParamSpec *pspec)
77 {
78         SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (object);
79
80         switch (prop_id) {
81         case PROP_MESSAGE:
82                 g_value_set_object (value, cistream->priv->msg);
83                 break;
84         default:
85                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
86                 break;
87         }
88 }
89
90 static gssize
91 soup_client_input_stream_read_fn (GInputStream  *stream,
92                                   void          *buffer,
93                                   gsize          count,
94                                   GCancellable  *cancellable,
95                                   GError       **error)
96 {
97         gssize nread;
98
99         nread = G_INPUT_STREAM_CLASS (soup_client_input_stream_parent_class)->
100                 read_fn (stream, buffer, count, cancellable, error);
101
102         if (nread == 0)
103                 g_signal_emit (stream, signals[EOF], 0);
104
105         return nread;
106 }
107
108 static gssize
109 soup_client_input_stream_read_nonblocking (GPollableInputStream  *stream,
110                                            void                  *buffer,
111                                            gsize                  count,
112                                            GError               **error)
113 {
114         gssize nread;
115
116         nread = soup_client_input_stream_parent_pollable_interface->
117                 read_nonblocking (stream, buffer, count, error);
118
119         if (nread == 0)
120                 g_signal_emit (stream, signals[EOF], 0);
121
122         return nread;
123 }
124
125 static gboolean
126 soup_client_input_stream_close_fn (GInputStream  *stream,
127                                    GCancellable  *cancellable,
128                                    GError       **error)
129 {
130         SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (stream);
131         gboolean success;
132
133         success = soup_message_io_run_until_finish (cistream->priv->msg, TRUE,
134                                                     NULL, error);
135         soup_message_io_finished (cistream->priv->msg);
136         return success;
137 }
138
139 static gboolean
140 idle_finish_close (gpointer user_data)
141 {
142         GTask *task = user_data;
143
144         g_task_return_boolean (task, TRUE);
145         g_object_unref (task);
146         return FALSE;
147 }
148
149 static gboolean
150 close_async_ready (SoupMessage *msg, gpointer user_data)
151 {
152         GTask *task = user_data;
153         SoupClientInputStream *cistream = g_task_get_source_object (task);
154         GError *error = NULL;
155
156         if (!soup_message_io_run_until_finish (cistream->priv->msg, FALSE,
157                                                g_task_get_cancellable (task),
158                                                &error) &&
159             g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
160                 g_error_free (error);
161                 return TRUE;
162         }
163
164         soup_message_io_finished (cistream->priv->msg);
165
166         if (error) {
167                 g_task_return_error (task, error);
168                 g_object_unref (task);
169                 return FALSE;
170         }
171
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.
175          */
176         soup_add_idle (g_main_context_get_thread_default (),
177                        idle_finish_close, task);
178         return FALSE;
179 }
180
181 static void
182 soup_client_input_stream_close_async (GInputStream        *stream,
183                                       gint                 priority,
184                                       GCancellable        *cancellable,
185                                       GAsyncReadyCallback  callback,
186                                       gpointer             user_data)
187 {
188         SoupClientInputStream *cistream = SOUP_CLIENT_INPUT_STREAM (stream);
189         GTask *task;
190         GSource *source;
191
192         task = g_task_new (stream, cancellable, callback, user_data);
193         g_task_set_priority (task, priority);
194
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);
198
199                 g_task_attach_source (task, source, (GSourceFunc) close_async_ready);
200                 g_source_unref (source);
201         }
202 }
203
204 static gboolean
205 soup_client_input_stream_close_finish (GInputStream  *stream,
206                                        GAsyncResult  *result,
207                                        GError       **error)
208 {
209         return g_task_propagate_boolean (G_TASK (result), error);
210 }
211
212 static void
213 soup_client_input_stream_class_init (SoupClientInputStreamClass *stream_class)
214 {
215         GObjectClass *object_class = G_OBJECT_CLASS (stream_class);
216         GInputStreamClass *input_stream_class = G_INPUT_STREAM_CLASS (stream_class);
217
218         g_type_class_add_private (stream_class, sizeof (SoupClientInputStreamPrivate));
219
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;
223
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;
228
229         signals[EOF] =
230                 g_signal_new ("eof",
231                               G_OBJECT_CLASS_TYPE (object_class),
232                               G_SIGNAL_RUN_LAST,
233                               0,
234                               NULL, NULL,
235                               NULL,
236                               G_TYPE_NONE, 0);
237
238         g_object_class_install_property (
239                 object_class, PROP_MESSAGE,
240                 g_param_spec_object ("message",
241                                      "Message",
242                                      "Message",
243                                      SOUP_TYPE_MESSAGE,
244                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
245 }
246
247 static void
248 soup_client_input_stream_pollable_init (GPollableInputStreamInterface *pollable_interface,
249                                         gpointer interface_data)
250 {
251         soup_client_input_stream_parent_pollable_interface =
252                 g_type_interface_peek_parent (pollable_interface);
253
254         pollable_interface->read_nonblocking = soup_client_input_stream_read_nonblocking;
255 }
256
257 GInputStream *
258 soup_client_input_stream_new (GInputStream *base_stream,
259                               SoupMessage  *msg)
260 {
261         return g_object_new (SOUP_TYPE_CLIENT_INPUT_STREAM,
262                              "base-stream", base_stream,
263                              "message", msg,
264                              NULL);
265 }