• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, 2010 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-lib.h>
29 
30 #include "soup-request.h"
31 #include "soup.h"
32 #include "soup-requester.h"
33 
34 /**
35  * SECTION:soup-request
36  * @short_description: Protocol-independent streaming request interface
37  *
38  * A #SoupRequest is created by #SoupSession, and represents a request
39  * to retrieve a particular URI.
40  */
41 
42 /**
43  * SoupRequest:
44  *
45  * A request to retrieve a particular URI.
46  *
47  * Since: 2.42
48  */
49 
50 enum {
51 	PROP_0,
52 	PROP_URI,
53 	PROP_SESSION
54 };
55 
56 struct _SoupRequestPrivate {
57 	SoupURI *uri;
58 	SoupSession *session;
59 };
60 
61 static void soup_request_initable_interface_init (GInitableIface *initable_interface);
62 
G_DEFINE_TYPE_WITH_CODE(SoupRequest,soup_request,G_TYPE_OBJECT,G_ADD_PRIVATE (SoupRequest)G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,soup_request_initable_interface_init))63 G_DEFINE_TYPE_WITH_CODE (SoupRequest, soup_request, G_TYPE_OBJECT,
64                          G_ADD_PRIVATE (SoupRequest)
65 			 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
66 						soup_request_initable_interface_init))
67 
68 static void
69 soup_request_init (SoupRequest *request)
70 {
71 	request->priv = soup_request_get_instance_private (request);
72 }
73 
74 static void
soup_request_finalize(GObject * object)75 soup_request_finalize (GObject *object)
76 {
77 	SoupRequest *request = SOUP_REQUEST (object);
78 
79 	g_clear_pointer (&request->priv->uri, soup_uri_free);
80 	g_clear_object (&request->priv->session);
81 
82 	G_OBJECT_CLASS (soup_request_parent_class)->finalize (object);
83 }
84 
85 static void
soup_request_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)86 soup_request_set_property (GObject      *object,
87 			   guint prop_id,
88 			   const GValue *value,
89 			   GParamSpec   *pspec)
90 {
91 	SoupRequest *request = SOUP_REQUEST (object);
92 
93 	switch (prop_id) {
94 	case PROP_URI:
95 		if (request->priv->uri)
96 			soup_uri_free (request->priv->uri);
97 		request->priv->uri = g_value_dup_boxed (value);
98 		break;
99 	case PROP_SESSION:
100 		if (request->priv->session)
101 			g_object_unref (request->priv->session);
102 		request->priv->session = g_value_dup_object (value);
103 		break;
104 	default:
105 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
106 		break;
107 	}
108 }
109 
110 static void
soup_request_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)111 soup_request_get_property (GObject    *object,
112 			   guint prop_id,
113 			   GValue     *value,
114 			   GParamSpec *pspec)
115 {
116 	SoupRequest *request = SOUP_REQUEST (object);
117 
118 	switch (prop_id) {
119 	case PROP_URI:
120 		g_value_set_boxed (value, request->priv->uri);
121 		break;
122 	case PROP_SESSION:
123 		g_value_set_object (value, request->priv->session);
124 		break;
125 	default:
126 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
127 		break;
128 	}
129 }
130 
131 static gboolean
soup_request_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)132 soup_request_initable_init (GInitable     *initable,
133 			    GCancellable  *cancellable,
134 			    GError       **error)
135 {
136 	SoupRequest *request = SOUP_REQUEST (initable);
137 	gboolean ok;
138 
139 	if (!request->priv->uri) {
140 		g_set_error (error, SOUP_REQUEST_ERROR, SOUP_REQUEST_ERROR_BAD_URI,
141 			     _("No URI provided"));
142 		return FALSE;
143 	}
144 
145 	ok = SOUP_REQUEST_GET_CLASS (initable)->
146 		check_uri (request, request->priv->uri, error);
147 
148 	if (!ok && error && !*error) {
149 		char *uri_string = soup_uri_to_string (request->priv->uri, FALSE);
150 		g_set_error (error, SOUP_REQUEST_ERROR, SOUP_REQUEST_ERROR_BAD_URI,
151 			     _("Invalid “%s” URI: %s"),
152 			     request->priv->uri->scheme,
153 			     uri_string);
154 		g_free (uri_string);
155 	}
156 
157 	return ok;
158 }
159 
160 static gboolean
soup_request_default_check_uri(SoupRequest * request,SoupURI * uri,GError ** error)161 soup_request_default_check_uri (SoupRequest  *request,
162 				SoupURI      *uri,
163 				GError      **error)
164 {
165 	return TRUE;
166 }
167 
168 /* Default implementation: assume the sync implementation doesn't block */
169 static void
soup_request_default_send_async(SoupRequest * request,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)170 soup_request_default_send_async (SoupRequest          *request,
171 				 GCancellable         *cancellable,
172 				 GAsyncReadyCallback   callback,
173 				 gpointer              user_data)
174 {
175 	GTask *task;
176 	GInputStream *stream;
177 	GError *error = NULL;
178 
179 	task = g_task_new (request, cancellable, callback, user_data);
180 
181 	stream = soup_request_send (request, cancellable, &error);
182 	if (stream)
183 		g_task_return_pointer (task, stream, g_object_unref);
184 	else
185 		g_task_return_error (task, error);
186 	g_object_unref (task);
187 }
188 
189 static GInputStream *
soup_request_default_send_finish(SoupRequest * request,GAsyncResult * result,GError ** error)190 soup_request_default_send_finish (SoupRequest          *request,
191 				  GAsyncResult         *result,
192 				  GError              **error)
193 {
194 	return g_task_propagate_pointer (G_TASK (result), error);
195 }
196 
197 /**
198  * soup_request_send:
199  * @request: a #SoupRequest
200  * @cancellable: a #GCancellable or %NULL
201  * @error: return location for a #GError, or %NULL
202  *
203  * Synchronously requests the URI pointed to by @request, and returns
204  * a #GInputStream that can be used to read its contents.
205  *
206  * Note that you cannot use this method with #SoupRequests attached to
207  * a #SoupSessionAsync.
208  *
209  * Return value: (transfer full): a #GInputStream that can be used to
210  *   read from the URI pointed to by @request.
211  *
212  * Since: 2.42
213  */
214 GInputStream *
soup_request_send(SoupRequest * request,GCancellable * cancellable,GError ** error)215 soup_request_send (SoupRequest          *request,
216 		   GCancellable         *cancellable,
217 		   GError              **error)
218 {
219 	return SOUP_REQUEST_GET_CLASS (request)->
220 		send (request, cancellable, error);
221 }
222 
223 /**
224  * soup_request_send_async:
225  * @request: a #SoupRequest
226  * @cancellable: a #GCancellable or %NULL
227  * @callback: a #GAsyncReadyCallback
228  * @user_data: user data passed to @callback
229  *
230  * Begins an asynchronously request for the URI pointed to by
231  * @request.
232  *
233  * Note that you cannot use this method with #SoupRequests attached to
234  * a #SoupSessionSync.
235  *
236  * Since: 2.42
237  */
238 void
soup_request_send_async(SoupRequest * request,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)239 soup_request_send_async (SoupRequest         *request,
240 			 GCancellable        *cancellable,
241 			 GAsyncReadyCallback  callback,
242 			 gpointer             user_data)
243 {
244 	SOUP_REQUEST_GET_CLASS (request)->
245 		send_async (request, cancellable, callback, user_data);
246 }
247 
248 /**
249  * soup_request_send_finish:
250  * @request: a #SoupRequest
251  * @result: the #GAsyncResult
252  * @error: return location for a #GError, or %NULL
253  *
254  * Gets the result of a soup_request_send_async().
255  *
256  * Return value: (transfer full): a #GInputStream that can be used to
257  *   read from the URI pointed to by @request.
258  *
259  * Since: 2.42
260  */
261 GInputStream *
soup_request_send_finish(SoupRequest * request,GAsyncResult * result,GError ** error)262 soup_request_send_finish (SoupRequest          *request,
263 			  GAsyncResult         *result,
264 			  GError              **error)
265 {
266 	return SOUP_REQUEST_GET_CLASS (request)->
267 		send_finish (request, result, error);
268 }
269 
270 static void
soup_request_class_init(SoupRequestClass * request_class)271 soup_request_class_init (SoupRequestClass *request_class)
272 {
273 	GObjectClass *object_class = G_OBJECT_CLASS (request_class);
274 
275 	request_class->check_uri = soup_request_default_check_uri;
276 	request_class->send_async = soup_request_default_send_async;
277 	request_class->send_finish = soup_request_default_send_finish;
278 
279 	object_class->finalize = soup_request_finalize;
280 	object_class->set_property = soup_request_set_property;
281 	object_class->get_property = soup_request_get_property;
282 
283 	/**
284 	 * SOUP_REQUEST_URI:
285 	 *
286 	 * Alias for the #SoupRequest:uri property, qv.
287 	 *
288 	 * Since: 2.42
289 	 */
290 	/**
291 	 * SoupRequest:uri:
292 	 *
293 	 * The request URI.
294 	 *
295 	 * Since: 2.42
296 	 */
297 	g_object_class_install_property (
298 		 object_class, PROP_URI,
299 		 g_param_spec_boxed (SOUP_REQUEST_URI,
300 				     "URI",
301 				     "The request URI",
302 				     SOUP_TYPE_URI,
303 				     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
304 				     G_PARAM_STATIC_STRINGS));
305 	/**
306 	 * SOUP_REQUEST_SESSION:
307 	 *
308 	 * Alias for the #SoupRequest:session property, qv.
309 	 *
310 	 * Since: 2.42
311 	 */
312 	/**
313 	 * SoupRequest:session:
314 	 *
315 	 * The request's #SoupSession.
316 	 *
317 	 * Since: 2.42
318 	 */
319 	g_object_class_install_property (
320 		 object_class, PROP_SESSION,
321 		 g_param_spec_object (SOUP_REQUEST_SESSION,
322 				      "Session",
323 				      "The request's session",
324 				      SOUP_TYPE_SESSION,
325 				      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
326 				      G_PARAM_STATIC_STRINGS));
327 }
328 
329 static void
soup_request_initable_interface_init(GInitableIface * initable_interface)330 soup_request_initable_interface_init (GInitableIface *initable_interface)
331 {
332 	initable_interface->init = soup_request_initable_init;
333 }
334 
335 /**
336  * soup_request_get_uri:
337  * @request: a #SoupRequest
338  *
339  * Gets @request's URI
340  *
341  * Return value: (transfer none): @request's URI
342  *
343  * Since: 2.42
344  */
345 SoupURI *
soup_request_get_uri(SoupRequest * request)346 soup_request_get_uri (SoupRequest *request)
347 {
348 	return request->priv->uri;
349 }
350 
351 /**
352  * soup_request_get_session:
353  * @request: a #SoupRequest
354  *
355  * Gets @request's #SoupSession
356  *
357  * Return value: (transfer none): @request's #SoupSession
358  *
359  * Since: 2.42
360  */
361 SoupSession *
soup_request_get_session(SoupRequest * request)362 soup_request_get_session (SoupRequest *request)
363 {
364 	return request->priv->session;
365 }
366 
367 /**
368  * soup_request_get_content_length:
369  * @request: a #SoupRequest
370  *
371  * Gets the length of the data represented by @request. For most
372  * request types, this will not be known until after you call
373  * soup_request_send() or soup_request_send_finish().
374  *
375  * Return value: the length of the data represented by @request,
376  *   or -1 if not known.
377  *
378  * Since: 2.42
379  */
380 goffset
soup_request_get_content_length(SoupRequest * request)381 soup_request_get_content_length (SoupRequest *request)
382 {
383 	return SOUP_REQUEST_GET_CLASS (request)->get_content_length (request);
384 }
385 
386 /**
387  * soup_request_get_content_type:
388  * @request: a #SoupRequest
389  *
390  * Gets the type of the data represented by @request. For most request
391  * types, this will not be known until after you call
392  * soup_request_send() or soup_request_send_finish().
393  *
394  * As in the HTTP Content-Type header, this may include parameters
395  * after the MIME type.
396  *
397  * Return value: (nullable): the type of the data represented by
398  *   @request, or %NULL if not known.
399  *
400  * Since: 2.42
401  */
402 const char *
soup_request_get_content_type(SoupRequest * request)403 soup_request_get_content_type (SoupRequest  *request)
404 {
405 	return SOUP_REQUEST_GET_CLASS (request)->get_content_type (request);
406 }
407