soup-auth-manager: add soup_auth_manager_use_auth()
[platform/upstream/libsoup.git] / libsoup / soup-filter-input-stream.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-filter-input-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 <string.h>
13
14 #include "soup-filter-input-stream.h"
15 #include "soup.h"
16
17 /* This is essentially a subset of GDataInputStream, except that we
18  * can do the equivalent of "fill_nonblocking()" on it. (We could use
19  * an actual GDataInputStream, and implement the nonblocking semantics
20  * via fill_async(), but that would be more work...)
21  */
22
23 struct _SoupFilterInputStreamPrivate {
24         GByteArray *buf;
25         gboolean need_more;
26 };
27
28 static void soup_filter_input_stream_pollable_init (GPollableInputStreamInterface *pollable_interface, gpointer interface_data);
29
30 G_DEFINE_TYPE_WITH_CODE (SoupFilterInputStream, soup_filter_input_stream, G_TYPE_FILTER_INPUT_STREAM,
31                          G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM,
32                                                 soup_filter_input_stream_pollable_init))
33
34 static void
35 soup_filter_input_stream_init (SoupFilterInputStream *stream)
36 {
37         stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
38                                                     SOUP_TYPE_FILTER_INPUT_STREAM,
39                                                     SoupFilterInputStreamPrivate);
40 }
41
42 static void
43 soup_filter_input_stream_finalize (GObject *object)
44 {
45         SoupFilterInputStream *fstream = SOUP_FILTER_INPUT_STREAM (object);
46
47         g_clear_pointer (&fstream->priv->buf, g_byte_array_unref);
48
49         G_OBJECT_CLASS (soup_filter_input_stream_parent_class)->finalize (object);
50 }
51
52 static gssize
53 read_from_buf (SoupFilterInputStream *fstream, gpointer buffer, gsize count)
54 {
55         GByteArray *buf = fstream->priv->buf;
56
57         if (buf->len < count)
58                 count = buf->len;
59         memcpy (buffer, buf->data, count);
60
61         if (count == buf->len) {
62                 g_byte_array_free (buf, TRUE);
63                 fstream->priv->buf = NULL;
64         } else {
65                 memmove (buf->data, buf->data + count,
66                          buf->len - count);
67                 g_byte_array_set_size (buf, buf->len - count);
68         }
69
70         return count;
71 }
72
73 static gssize
74 soup_filter_input_stream_read_fn (GInputStream  *stream,
75                                   void          *buffer,
76                                   gsize          count,
77                                   GCancellable  *cancellable,
78                                   GError       **error)
79 {
80         SoupFilterInputStream *fstream = SOUP_FILTER_INPUT_STREAM (stream);
81
82         fstream->priv->need_more = FALSE;
83         if (fstream->priv->buf) {
84                 return read_from_buf (fstream, buffer, count);
85         } else {
86                 return g_pollable_stream_read (G_FILTER_INPUT_STREAM (fstream)->base_stream,
87                                                buffer, count,
88                                                TRUE, cancellable, error);
89         }
90 }
91
92 static gboolean
93 soup_filter_input_stream_is_readable (GPollableInputStream *stream)
94 {
95         SoupFilterInputStream *fstream = SOUP_FILTER_INPUT_STREAM (stream);
96
97         if (fstream->priv->buf && !fstream->priv->need_more)
98                 return TRUE;
99         else
100                 return g_pollable_input_stream_is_readable (G_POLLABLE_INPUT_STREAM (G_FILTER_INPUT_STREAM (fstream)->base_stream));
101 }
102
103 static gssize
104 soup_filter_input_stream_read_nonblocking (GPollableInputStream  *stream,
105                                            void                  *buffer,
106                                            gsize                  count,
107                                            GError               **error)
108 {
109         SoupFilterInputStream *fstream = SOUP_FILTER_INPUT_STREAM (stream);
110
111         fstream->priv->need_more = FALSE;
112         if (fstream->priv->buf) {
113                 return read_from_buf (fstream, buffer, count);
114         } else {
115                 return g_pollable_stream_read (G_FILTER_INPUT_STREAM (fstream)->base_stream,
116                                                buffer, count,
117                                                FALSE, NULL, error);
118         }
119 }
120
121 static GSource *
122 soup_filter_input_stream_create_source (GPollableInputStream *stream,
123                                         GCancellable         *cancellable)
124 {
125         SoupFilterInputStream *fstream = SOUP_FILTER_INPUT_STREAM (stream);
126         GSource *base_source, *pollable_source;
127
128         if (fstream->priv->buf && !fstream->priv->need_more)
129                 base_source = g_timeout_source_new (0);
130         else
131                 base_source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (G_FILTER_INPUT_STREAM (fstream)->base_stream), cancellable);
132
133         g_source_set_dummy_callback (base_source);
134         pollable_source = g_pollable_source_new (G_OBJECT (stream));
135         g_source_add_child_source (pollable_source, base_source);
136         g_source_unref (base_source);
137
138         return pollable_source;
139 }
140
141 static void
142 soup_filter_input_stream_class_init (SoupFilterInputStreamClass *stream_class)
143 {
144         GObjectClass *object_class = G_OBJECT_CLASS (stream_class);
145         GInputStreamClass *input_stream_class = G_INPUT_STREAM_CLASS (stream_class);
146
147         g_type_class_add_private (stream_class, sizeof (SoupFilterInputStreamPrivate));
148
149         object_class->finalize = soup_filter_input_stream_finalize;
150
151         input_stream_class->read_fn = soup_filter_input_stream_read_fn;
152 }
153
154 static void
155 soup_filter_input_stream_pollable_init (GPollableInputStreamInterface *pollable_interface,
156                                         gpointer                       interface_data)
157 {
158         pollable_interface->is_readable = soup_filter_input_stream_is_readable;
159         pollable_interface->read_nonblocking = soup_filter_input_stream_read_nonblocking;
160         pollable_interface->create_source = soup_filter_input_stream_create_source;
161 }
162
163 GInputStream *
164 soup_filter_input_stream_new (GInputStream *base_stream)
165 {
166         return g_object_new (SOUP_TYPE_FILTER_INPUT_STREAM,
167                              "base-stream", base_stream,
168                              "close-base-stream", FALSE,
169                              NULL);
170 }
171
172 gssize
173 soup_filter_input_stream_read_line (SoupFilterInputStream  *fstream,
174                                     void                   *buffer,
175                                     gsize                   length,
176                                     gboolean                blocking,
177                                     gboolean               *got_line,
178                                     GCancellable           *cancellable,
179                                     GError                **error)
180 {
181         return soup_filter_input_stream_read_until (fstream, buffer, length,
182                                                     "\n", 1, blocking,
183                                                     TRUE, got_line,
184                                                     cancellable, error);
185 }
186
187 gssize
188 soup_filter_input_stream_read_until (SoupFilterInputStream  *fstream,
189                                      void                   *buffer,
190                                      gsize                   length,
191                                      const void             *boundary,
192                                      gsize                   boundary_length,
193                                      gboolean                blocking,
194                                      gboolean                include_boundary,
195                                      gboolean               *got_boundary,
196                                      GCancellable           *cancellable,
197                                      GError                **error)
198 {
199         gssize nread;
200         guint8 *p, *buf, *end;
201         gboolean eof = FALSE;
202         GError *my_error = NULL;
203
204         g_return_val_if_fail (SOUP_IS_FILTER_INPUT_STREAM (fstream), -1);
205         g_return_val_if_fail (!include_boundary || (boundary_length < length), -1);
206
207         *got_boundary = FALSE;
208         fstream->priv->need_more = FALSE;
209
210         if (!fstream->priv->buf || fstream->priv->buf->len < boundary_length) {
211                 guint prev_len;
212
213         fill_buffer:
214                 if (!fstream->priv->buf)
215                         fstream->priv->buf = g_byte_array_new ();
216                 prev_len = fstream->priv->buf->len;
217                 g_byte_array_set_size (fstream->priv->buf, length);
218                 buf = fstream->priv->buf->data;
219
220                 nread = g_pollable_stream_read (G_FILTER_INPUT_STREAM (fstream)->base_stream,
221                                                 buf + prev_len, length - prev_len,
222                                                 blocking,
223                                                 cancellable, &my_error);
224                 if (nread <= 0) {
225                         if (prev_len)
226                                 fstream->priv->buf->len = prev_len;
227                         else {
228                                 g_byte_array_free (fstream->priv->buf, TRUE);
229                                 fstream->priv->buf = NULL;
230                         }
231
232                         if (nread == 0 && prev_len)
233                                 eof = TRUE;
234                         else {
235                                 if (g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
236                                         fstream->priv->need_more = TRUE;
237                                 if (my_error)
238                                         g_propagate_error (error, my_error);
239
240                                 return nread;
241                         }
242
243                         if (my_error)
244                                 g_propagate_error (error, my_error);
245                 } else
246                         fstream->priv->buf->len = prev_len + nread;
247         } else
248                 buf = fstream->priv->buf->data;
249
250         /* Scan for the boundary */
251         end = buf + fstream->priv->buf->len;
252         if (!eof)
253                 end -= boundary_length;
254         for (p = buf; p <= end; p++) {
255                 if (*p == *(guint8*)boundary &&
256                     !memcmp (p, boundary, boundary_length)) {
257                         if (include_boundary)
258                                 p += boundary_length;
259                         *got_boundary = TRUE;
260                         break;
261                 }
262         }
263
264         if (!*got_boundary && fstream->priv->buf->len < length && !eof)
265                 goto fill_buffer;
266
267         /* Return everything up to 'p' (which is either just after the boundary if
268          * include_boundary is TRUE, just before the boundary if include_boundary is
269          * FALSE, @boundary_len - 1 bytes before the end of the buffer, or end-of-
270          * file).
271          */
272         return read_from_buf (fstream, buffer, p - buf);
273 }