2010-10-13 Sergio Villar Senin <svillar@igalia.com>
[WebKit-https.git] / WebCore / platform / network / soup / cache / soup-request.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-request.c: Protocol-independent streaming request interface
4  *
5  * Copyright (C) 2009 Red Hat, Inc.
6  * Copyright (C) 2010, Igalia S.L.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <glib/gi18n.h>
29
30 #include "soup-request.h"
31 #include "soup-requester.h"
32
33 /**
34  * SECTION:soup-request
35  * @short_description: Protocol-independent streaming request interface
36  *
37  * FIXME
38  **/
39
40 /**
41  * WebKitSoupRequest:
42  *
43  * FIXME
44  *
45  * Since: 2.30
46  **/
47
48 static void webkit_soup_request_initable_interface_init (GInitableIface *initable_interface);
49
50 G_DEFINE_TYPE_WITH_CODE (WebKitSoupRequest, webkit_soup_request, G_TYPE_OBJECT,
51                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
52                                                 webkit_soup_request_initable_interface_init))
53
54 enum {
55         PROP_0,
56         PROP_URI,
57         PROP_SESSION
58 };
59
60 struct _WebKitSoupRequestPrivate {
61         SoupURI *uri;
62         SoupSession *session;
63 };
64
65 static void
66 webkit_soup_request_init (WebKitSoupRequest *request)
67 {
68         request->priv = G_TYPE_INSTANCE_GET_PRIVATE (request, WEBKIT_TYPE_SOUP_REQUEST, WebKitSoupRequestPrivate);
69 }
70
71 static void
72 webkit_soup_request_finalize (GObject *object)
73 {
74         WebKitSoupRequest *request = WEBKIT_SOUP_REQUEST (object);
75
76         if (request->priv->uri)
77                 soup_uri_free (request->priv->uri);
78         if (request->priv->session)
79                 g_object_unref (request->priv->session);
80
81         G_OBJECT_CLASS (webkit_soup_request_parent_class)->finalize (object);
82 }
83
84 static void
85 webkit_soup_request_set_property (GObject      *object,
86                                   guint prop_id,
87                                   const GValue *value,
88                                   GParamSpec   *pspec)
89 {
90         WebKitSoupRequest *request = WEBKIT_SOUP_REQUEST (object);
91
92         switch (prop_id) {
93         case PROP_URI:
94                 if (request->priv->uri)
95                         soup_uri_free (request->priv->uri);
96                 request->priv->uri = g_value_dup_boxed (value);
97                 break;
98         case PROP_SESSION:
99                 if (request->priv->session)
100                         g_object_unref (request->priv->session);
101                 request->priv->session = g_value_dup_object (value);
102                 break;
103         default:
104                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
105                 break;
106         }
107 }
108
109 static void
110 webkit_soup_request_get_property (GObject    *object,
111                                   guint prop_id,
112                                   GValue     *value,
113                                   GParamSpec *pspec)
114 {
115         WebKitSoupRequest *request = WEBKIT_SOUP_REQUEST (object);
116
117         switch (prop_id) {
118         case PROP_URI:
119                 g_value_set_boxed (value, request->priv->uri);
120                 break;
121         case PROP_SESSION:
122                 g_value_set_object (value, request->priv->session);
123                 break;
124         default:
125                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
126                 break;
127         }
128 }
129
130 static gboolean
131 webkit_soup_request_initable_init (GInitable     *initable,
132                                    GCancellable  *cancellable,
133                                    GError       **error)
134 {
135         WebKitSoupRequest *request = WEBKIT_SOUP_REQUEST (initable);
136         gboolean ok;
137
138         if (!request->priv->uri) {
139                 g_set_error (error, WEBKIT_SOUP_ERROR, WEBKIT_SOUP_ERROR_BAD_URI,
140                              _ ("No URI provided"));
141                 return FALSE;
142         }
143
144         ok = WEBKIT_SOUP_REQUEST_GET_CLASS (initable)->
145                 check_uri (request, request->priv->uri, error);
146
147         if (!ok && error) {
148                 char *uri_string = soup_uri_to_string (request->priv->uri, FALSE);
149                 g_set_error (error, WEBKIT_SOUP_ERROR, WEBKIT_SOUP_ERROR_BAD_URI,
150                              _ ("Invalid '%s' URI: %s"),
151                              request->priv->uri->scheme,
152                              uri_string);
153                 g_free (uri_string);
154         }
155
156         return ok;
157 }
158
159 static gboolean
160 webkit_soup_request_default_check_uri (WebKitSoupRequest  *request,
161                                        SoupURI      *uri,
162                                        GError      **error)
163 {
164         return TRUE;
165 }
166
167 /* Default implementation: assume the sync implementation doesn't block */
168 static void
169 webkit_soup_request_default_send_async (WebKitSoupRequest          *request,
170                                         GCancellable         *cancellable,
171                                         GAsyncReadyCallback callback,
172                                         gpointer user_data)
173 {
174         GSimpleAsyncResult *simple;
175
176         simple = g_simple_async_result_new (G_OBJECT (request),
177                                             callback, user_data,
178                                             webkit_soup_request_default_send_async);
179         g_simple_async_result_complete_in_idle (simple);
180         g_object_unref (simple);
181 }
182
183 static GInputStream *
184 webkit_soup_request_default_send_finish (WebKitSoupRequest          *request,
185                                          GAsyncResult         *result,
186                                          GError              **error)
187 {
188         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (request), webkit_soup_request_default_send_async), NULL);
189
190         return webkit_soup_request_send (request, NULL, error);
191 }
192
193 GInputStream *
194 webkit_soup_request_send (WebKitSoupRequest          *request,
195                           GCancellable         *cancellable,
196                           GError              **error)
197 {
198         return WEBKIT_SOUP_REQUEST_GET_CLASS (request)->
199                 send (request, cancellable, error);
200 }
201
202 void
203 webkit_soup_request_send_async (WebKitSoupRequest          *request,
204                                 GCancellable         *cancellable,
205                                 GAsyncReadyCallback callback,
206                                 gpointer user_data)
207 {
208         WEBKIT_SOUP_REQUEST_GET_CLASS (request)->
209                 send_async (request, cancellable, callback, user_data);
210 }
211
212 GInputStream *
213 webkit_soup_request_send_finish (WebKitSoupRequest          *request,
214                                  GAsyncResult         *result,
215                                  GError              **error)
216 {
217         return WEBKIT_SOUP_REQUEST_GET_CLASS (request)->
218                 send_finish (request, result, error);
219 }
220
221 static void
222 webkit_soup_request_class_init (WebKitSoupRequestClass *request_class)
223 {
224         GObjectClass *object_class = G_OBJECT_CLASS (request_class);
225
226         g_type_class_add_private (request_class, sizeof (WebKitSoupRequestPrivate));
227
228         request_class->check_uri = webkit_soup_request_default_check_uri;
229         request_class->send_async = webkit_soup_request_default_send_async;
230         request_class->send_finish = webkit_soup_request_default_send_finish;
231
232         object_class->finalize = webkit_soup_request_finalize;
233         object_class->set_property = webkit_soup_request_set_property;
234         object_class->get_property = webkit_soup_request_get_property;
235
236         g_object_class_install_property (
237                  object_class, PROP_URI,
238                  g_param_spec_boxed (WEBKIT_SOUP_REQUEST_URI,
239                                      "URI",
240                                      "The request URI",
241                                      SOUP_TYPE_URI,
242                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
243         g_object_class_install_property (
244                  object_class, PROP_SESSION,
245                  g_param_spec_object (WEBKIT_SOUP_REQUEST_SESSION,
246                                       "Session",
247                                       "The request's session",
248                                       SOUP_TYPE_SESSION,
249                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
250 }
251
252 static void
253 webkit_soup_request_initable_interface_init (GInitableIface *initable_interface)
254 {
255         initable_interface->init = webkit_soup_request_initable_init;
256 }
257
258 SoupURI *
259 webkit_soup_request_get_uri (WebKitSoupRequest *request)
260 {
261         return request->priv->uri;
262 }
263
264 SoupSession *
265 webkit_soup_request_get_session (WebKitSoupRequest *request)
266 {
267         return request->priv->session;
268 }
269
270 goffset
271 webkit_soup_request_get_content_length (WebKitSoupRequest *request)
272 {
273         return WEBKIT_SOUP_REQUEST_GET_CLASS (request)->get_content_length (request);
274 }
275
276 const char *
277 webkit_soup_request_get_content_type (WebKitSoupRequest  *request)
278 {
279         return WEBKIT_SOUP_REQUEST_GET_CLASS (request)->get_content_type (request);
280 }
281
282 #define XDIGIT(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - 'A' + 10)
283 #define HEXCHAR(s) ((XDIGIT (s[1]) << 4) + XDIGIT (s[2]))
284
285 /* Copy&pasted from libsoup's soup-uri.c after applying the patch in
286  * https://bugzilla.gnome.org/show_bug.cgi?id=630540. We need this
287  * instead of soup_uri_decode() as it incorrectly returns NULL for
288  * incorrectly encoded URLs. TODO: remove this when required libsoup
289  * version is bumped out to 2.32.1
290  */
291 gchar *
292 webkit_soup_request_uri_decoded_copy (const char *part, int length)
293 {
294         unsigned char *s, *d;
295         char *decoded = g_strndup (part, length);
296
297         s = d = (unsigned char *)decoded;
298         do {
299                 if (*s == '%') {
300                         if (!g_ascii_isxdigit (s[1]) ||
301                             !g_ascii_isxdigit (s[2])) {
302                                 *d++ = *s;
303                                 continue;
304                         }
305                         *d++ = HEXCHAR (s);
306                         s += 2;
307                 } else
308                         *d++ = *s;
309         } while (*s++);
310
311         return decoded;
312 }