1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * soup-io-stream.c
4 *
5 * Copyright 2012 Red Hat, Inc.
6 */
7
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include "soup-io-stream.h"
13 #include "soup.h"
14 #include "soup-filter-input-stream.h"
15
16 struct _SoupIOStreamPrivate {
17 GIOStream *base_iostream;
18 gboolean close_on_dispose;
19
20 GInputStream *istream;
21 GOutputStream *ostream;
22 gboolean disposing;
23 };
24
25 enum {
26 PROP_0,
27
28 PROP_BASE_IOSTREAM,
29 PROP_CLOSE_ON_DISPOSE
30 };
31
G_DEFINE_TYPE_WITH_PRIVATE(SoupIOStream,soup_io_stream,G_TYPE_IO_STREAM)32 G_DEFINE_TYPE_WITH_PRIVATE (SoupIOStream, soup_io_stream, G_TYPE_IO_STREAM)
33
34 static void
35 soup_io_stream_init (SoupIOStream *stream)
36 {
37 stream->priv = soup_io_stream_get_instance_private (stream);
38 }
39
40 static void
soup_io_stream_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)41 soup_io_stream_set_property (GObject *object, guint prop_id,
42 const GValue *value, GParamSpec *pspec)
43 {
44 SoupIOStream *siostream = SOUP_IO_STREAM (object);
45 GIOStream *io;
46
47 switch (prop_id) {
48 case PROP_BASE_IOSTREAM:
49 io = siostream->priv->base_iostream = g_value_dup_object (value);
50 if (io) {
51 siostream->priv->istream =
52 soup_filter_input_stream_new (g_io_stream_get_input_stream (io));
53 siostream->priv->ostream =
54 g_object_ref (g_io_stream_get_output_stream (io));
55 } else {
56 g_clear_object (&siostream->priv->istream);
57 g_clear_object (&siostream->priv->ostream);
58 }
59 break;
60 case PROP_CLOSE_ON_DISPOSE:
61 siostream->priv->close_on_dispose = g_value_get_boolean (value);
62 break;
63 default:
64 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
65 break;
66 }
67 }
68
69 static void
soup_io_stream_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)70 soup_io_stream_get_property (GObject *object, guint prop_id,
71 GValue *value, GParamSpec *pspec)
72 {
73 SoupIOStream *siostream = SOUP_IO_STREAM (object);
74
75 switch (prop_id) {
76 case PROP_BASE_IOSTREAM:
77 g_value_set_object (value, siostream->priv->base_iostream);
78 break;
79 case PROP_CLOSE_ON_DISPOSE:
80 g_value_set_boolean (value, siostream->priv->close_on_dispose);
81 break;
82 default:
83 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
84 break;
85 }
86 }
87
88 static void
soup_io_stream_dispose(GObject * object)89 soup_io_stream_dispose (GObject *object)
90 {
91 SoupIOStream *siostream = SOUP_IO_STREAM (object);
92
93 siostream->priv->disposing = TRUE;
94
95 G_OBJECT_CLASS (soup_io_stream_parent_class)->dispose (object);
96 }
97
98 static void
soup_io_stream_finalize(GObject * object)99 soup_io_stream_finalize (GObject *object)
100 {
101 SoupIOStream *siostream = SOUP_IO_STREAM (object);
102
103 g_clear_object (&siostream->priv->base_iostream);
104 g_clear_object (&siostream->priv->istream);
105 g_clear_object (&siostream->priv->ostream);
106
107 G_OBJECT_CLASS (soup_io_stream_parent_class)->finalize (object);
108 }
109
110 static GInputStream *
soup_io_stream_get_input_stream(GIOStream * stream)111 soup_io_stream_get_input_stream (GIOStream *stream)
112 {
113 return SOUP_IO_STREAM (stream)->priv->istream;
114 }
115
116 static GOutputStream *
soup_io_stream_get_output_stream(GIOStream * stream)117 soup_io_stream_get_output_stream (GIOStream *stream)
118 {
119 return SOUP_IO_STREAM (stream)->priv->ostream;
120 }
121
122
123 static gboolean
soup_io_stream_close(GIOStream * stream,GCancellable * cancellable,GError ** error)124 soup_io_stream_close (GIOStream *stream,
125 GCancellable *cancellable,
126 GError **error)
127 {
128 SoupIOStream *siostream = SOUP_IO_STREAM (stream);
129
130 if (siostream->priv->disposing &&
131 !siostream->priv->close_on_dispose)
132 return TRUE;
133
134 return g_io_stream_close (siostream->priv->base_iostream,
135 cancellable, error);
136 }
137
138 static void
close_async_complete(GObject * object,GAsyncResult * result,gpointer user_data)139 close_async_complete (GObject *object,
140 GAsyncResult *result,
141 gpointer user_data)
142 {
143 GTask *task = user_data;
144 GError *error = NULL;
145
146 if (g_io_stream_close_finish (G_IO_STREAM (object), result, &error))
147 g_task_return_boolean (task, TRUE);
148 else
149 g_task_return_error (task, error);
150 g_object_unref (task);
151 }
152
153 static void
soup_io_stream_close_async(GIOStream * stream,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)154 soup_io_stream_close_async (GIOStream *stream,
155 int io_priority,
156 GCancellable *cancellable,
157 GAsyncReadyCallback callback,
158 gpointer user_data)
159 {
160 GTask *task;
161
162 task = g_task_new (stream, cancellable, callback, user_data);
163 g_io_stream_close_async (SOUP_IO_STREAM (stream)->priv->base_iostream,
164 io_priority, cancellable,
165 close_async_complete, task);
166 }
167
168 static gboolean
soup_io_stream_close_finish(GIOStream * stream,GAsyncResult * result,GError ** error)169 soup_io_stream_close_finish (GIOStream *stream,
170 GAsyncResult *result,
171 GError **error)
172 {
173 return g_task_propagate_boolean (G_TASK (result), error);
174 }
175
176 static void
soup_io_stream_class_init(SoupIOStreamClass * stream_class)177 soup_io_stream_class_init (SoupIOStreamClass *stream_class)
178 {
179 GObjectClass *object_class = G_OBJECT_CLASS (stream_class);
180 GIOStreamClass *io_stream_class = G_IO_STREAM_CLASS (stream_class);
181
182 object_class->set_property = soup_io_stream_set_property;
183 object_class->get_property = soup_io_stream_get_property;
184 object_class->dispose = soup_io_stream_dispose;
185 object_class->finalize = soup_io_stream_finalize;
186
187 io_stream_class->get_input_stream = soup_io_stream_get_input_stream;
188 io_stream_class->get_output_stream = soup_io_stream_get_output_stream;
189 io_stream_class->close_fn = soup_io_stream_close;
190 io_stream_class->close_async = soup_io_stream_close_async;
191 io_stream_class->close_finish = soup_io_stream_close_finish;
192
193 g_object_class_install_property (
194 object_class, PROP_BASE_IOSTREAM,
195 g_param_spec_object ("base-iostream",
196 "Base IOStream",
197 "Base GIOStream",
198 G_TYPE_IO_STREAM,
199 G_PARAM_READWRITE |
200 G_PARAM_CONSTRUCT_ONLY |
201 G_PARAM_STATIC_STRINGS));
202 g_object_class_install_property (
203 object_class, PROP_CLOSE_ON_DISPOSE,
204 g_param_spec_boolean ("close-on-dispose",
205 "Close base stream",
206 "Close base GIOStream when closing",
207 TRUE,
208 G_PARAM_READWRITE |
209 G_PARAM_CONSTRUCT_ONLY |
210 G_PARAM_STATIC_STRINGS));
211 }
212
213 GIOStream *
soup_io_stream_new(GIOStream * base_iostream,gboolean close_on_dispose)214 soup_io_stream_new (GIOStream *base_iostream,
215 gboolean close_on_dispose)
216 {
217 return g_object_new (SOUP_TYPE_IO_STREAM,
218 "base-iostream", base_iostream,
219 "close-on-dispose", close_on_dispose,
220 NULL);
221 }
222
223 GIOStream *
soup_io_stream_get_base_iostream(SoupIOStream * stream)224 soup_io_stream_get_base_iostream (SoupIOStream *stream)
225 {
226 g_return_val_if_fail (SOUP_IS_IO_STREAM (stream), NULL);
227
228 return stream->priv->base_iostream;
229 }
230