1 #include <string.h>
2 #include "gskurltransfer.h"
3 #include "../gskmemory.h"
4 
5 /**
6  * gsk_url_transfer_result_name:
7  *
8  * @result: the enumeration value.
9  *
10  * Convert a GskUrlTransferResult value
11  * into a human-readable string.
12  *
13  * returns: the constant string.
14  */
15 const char *
gsk_url_transfer_result_name(GskUrlTransferResult result)16 gsk_url_transfer_result_name (GskUrlTransferResult result)
17 {
18   switch (result)
19     {
20     case GSK_URL_TRANSFER_ERROR_BAD_REQUEST:
21       return "Error: Bad Request";
22     case GSK_URL_TRANSFER_ERROR_BAD_NAME:
23       return "Error: Bad Name";
24     case GSK_URL_TRANSFER_ERROR_NO_SERVER:
25       return "Error: No Server";
26     case GSK_URL_TRANSFER_ERROR_NOT_FOUND:
27       return "Error: Not Found";
28     case GSK_URL_TRANSFER_ERROR_SERVER_ERROR:
29       return "Error: Server Error";
30     case GSK_URL_TRANSFER_ERROR_UNSUPPORTED:
31       return "Error: Unsupported";
32     case GSK_URL_TRANSFER_ERROR_TIMED_OUT:
33       return "Error: Timed Out";
34     case GSK_URL_TRANSFER_ERROR_REDIRECT_LOOP:
35       return "Error: Redirect Loop";
36     case GSK_URL_TRANSFER_REDIRECT:
37       return "Redirect";
38     case GSK_URL_TRANSFER_CANCELLED:
39       return "Cancelled";
40     case GSK_URL_TRANSFER_SUCCESS:
41       return "Success";
42     default:
43       g_warning ("requested name of invalid transfer result %u", result);
44       g_return_val_if_reached (NULL);
45     }
46 }
47 
48 G_DEFINE_TYPE(GskUrlTransfer, gsk_url_transfer, G_TYPE_OBJECT);
49 
50 typedef enum
51 {
52   GSK_URL_TRANSFER_STATE_CONSTRUCTING,
53   GSK_URL_TRANSFER_STATE_STARTED,
54   GSK_URL_TRANSFER_STATE_DONE,
55   GSK_URL_TRANSFER_STATE_ERROR
56 } GskUrlTransferState;
57 
58 static inline void
gsk_url_transfer_redirect_free_1(GskUrlTransferRedirect * redirect)59 gsk_url_transfer_redirect_free_1 (GskUrlTransferRedirect *redirect)
60 {
61   g_object_unref (redirect->url);
62   if (redirect->request)
63     g_object_unref (redirect->request);
64   if (redirect->response)
65     g_object_unref (redirect->response);
66   g_free (redirect);
67 }
68 
69 static void
gsk_url_transfer_finalize(GObject * object)70 gsk_url_transfer_finalize (GObject *object)
71 {
72   GskUrlTransfer *transfer = GSK_URL_TRANSFER (object);
73   GskUrlTransferRedirect *redir_at;
74   g_assert (transfer->transfer_state != GSK_URL_TRANSFER_STATE_STARTED);
75 
76   if (transfer->url)
77     g_object_unref (transfer->url);
78   redir_at = transfer->first_redirect;
79   while (redir_at)
80     {
81       GskUrlTransferRedirect *next = redir_at->next;
82       gsk_url_transfer_redirect_free_1 (redir_at);
83       redir_at = next;
84     }
85   if (transfer->address)
86     g_object_unref (transfer->address);
87   if (transfer->address_hint)
88     g_object_unref (transfer->address_hint);
89 
90   /* may be available: protocol-specific headers */
91   if (transfer->request)
92     g_object_unref (transfer->request);
93   if (transfer->response)
94     g_object_unref (transfer->response);
95 
96   if (transfer->content)
97     g_object_unref (transfer->content);
98   if (transfer->upload_destroy != NULL)
99     (*transfer->upload_destroy) (transfer->upload_data);
100 
101   g_clear_error (&transfer->error);
102 
103   G_OBJECT_CLASS (gsk_url_transfer_parent_class)->finalize (object);
104 }
105 
106 static void
gsk_url_transfer_real_timed_out(GskUrlTransfer * transfer)107 gsk_url_transfer_real_timed_out (GskUrlTransfer *transfer)
108 {
109   gsk_url_transfer_take_error (transfer,
110                                g_error_new (GSK_G_ERROR_DOMAIN,
111                                             GSK_ERROR_OPERATION_TIMED_OUT,
112                                             "Transfer with URL timed out"));
113   if (transfer->transfer_state != GSK_URL_TRANSFER_STATE_DONE)
114     gsk_url_transfer_notify_done (transfer, GSK_URL_TRANSFER_ERROR_TIMED_OUT);
115 }
116 
117 static char    *
gsk_url_transfer_real_get_constructing_state(GskUrlTransfer * transfer)118 gsk_url_transfer_real_get_constructing_state (GskUrlTransfer *transfer)
119 {
120   if (transfer->url)
121     {
122       char *url_str = gsk_url_to_string (transfer->url);
123       char *rv = g_strdup_printf ("NOT STARTED: %s", url_str);
124       g_free (url_str);
125       return rv;
126     }
127   return g_strdup ("NOT STARTED: (no url)");
128 }
129 
130 static char    *
gsk_url_transfer_real_get_running_state(GskUrlTransfer * transfer)131 gsk_url_transfer_real_get_running_state (GskUrlTransfer *transfer)
132 {
133   if (transfer->url)
134     {
135       char *url_str = gsk_url_to_string (transfer->url);
136       char *rv = g_strdup_printf ("RUNNING: %s", url_str);
137       g_free (url_str);
138       return rv;
139     }
140   return g_strdup ("RUNNING: (no url!?!)");
141 }
142 
143 static char    *
gsk_url_transfer_real_get_done_state(GskUrlTransfer * transfer)144 gsk_url_transfer_real_get_done_state (GskUrlTransfer *transfer)
145 {
146   if (transfer->url)
147     {
148       char *url_str = gsk_url_to_string (transfer->url);
149       char *rv = g_strdup_printf ("DONE: %s: %s", url_str,
150                           gsk_url_transfer_result_name (transfer->result));
151       g_free (url_str);
152       return rv;
153     }
154   return g_strdup_printf ("DONE: [no url]: %s",
155                           gsk_url_transfer_result_name (transfer->result));
156 }
157 
158 static void
gsk_url_transfer_init(GskUrlTransfer * transfer)159 gsk_url_transfer_init (GskUrlTransfer *transfer)
160 {
161   transfer->transfer_state = GSK_URL_TRANSFER_STATE_CONSTRUCTING;
162   transfer->follow_redirects = 1;
163 }
164 
165 static void
gsk_url_transfer_class_init(GskUrlTransferClass * transfer_class)166 gsk_url_transfer_class_init (GskUrlTransferClass *transfer_class)
167 {
168   GObjectClass *object_class = G_OBJECT_CLASS (transfer_class);
169   object_class->finalize = gsk_url_transfer_finalize;
170   transfer_class->timed_out = gsk_url_transfer_real_timed_out;
171   transfer_class->get_constructing_state = gsk_url_transfer_real_get_constructing_state;
172   transfer_class->get_running_state = gsk_url_transfer_real_get_running_state;
173   transfer_class->get_done_state = gsk_url_transfer_real_get_done_state;
174 }
175 
176 
177 /**
178  * gsk_url_transfer:
179  * @url: the URL to which to upload or from which to download data.
180  * @upload_func: optional function that can create the upload's content
181  * as a #GskStream.
182  * @upload_data: data which can be used by the upload function.
183  * @upload_destroy: optional function that will be notified when upload()
184  * will no longer be called (note that the streams it created may
185  * still be extant though).
186  * @handler: function to be called with the transfer request is
187  * done.  (The transfer content itself is just provided as a stream
188  * though-- only after reading the stream is the transfer truly done)
189  * This function may also be called in a number of error cases.
190  * @data: data to pass to the handler function.
191  * @destroy: function to call when you are done with data.
192  * @error: place to put the error if anything goes wrong.
193  *
194  * Begin a upload and/or download with a URL.
195  * There is no way to cancel this transfer.
196  *
197  * If you wish to perform an upload,
198  * provide a function that can create the stream of content to
199  * upload on demand.  Note that the upload_destroy() method
200  * is called only once the transfer is done and all the upload streams
201  * are finalized.  Therefore, you can assume that the upload_data
202  * will be available for all your upload-streams.
203  *
204  * The handler/data/destroy triple is used for result notification.
205  * handler() is always invoked exactly once.  To find out how things
206  * went, the handler() should almost always start by
207  * examining transfer->result.
208  *
209  * returns: whether the transfer began.
210  * Unsupported URL schemes and malformed URLs are the
211  * most common ways for this function to fail.
212  */
213 gboolean
gsk_url_transfer(GskUrl * url,GskUrlUploadFunc upload_func,gpointer upload_data,GDestroyNotify upload_destroy,GskUrlTransferFunc handler,gpointer data,GDestroyNotify destroy,GError ** error)214 gsk_url_transfer            (GskUrl            *url,
215                              GskUrlUploadFunc   upload_func,
216                              gpointer           upload_data,
217                              GDestroyNotify     upload_destroy,
218                              GskUrlTransferFunc handler,
219                              gpointer           data,
220                              GDestroyNotify     destroy,
221                              GError           **error)
222 {
223   GskUrlTransfer *transfer = gsk_url_transfer_new (url);
224   if (transfer == NULL)
225     {
226       g_set_error (error,
227                    GSK_G_ERROR_DOMAIN,
228                    GSK_ERROR_INVALID_ARGUMENT,
229                    "could not create Transfer object for url of scheme %s", url->scheme_name);
230       return FALSE;
231     }
232   gsk_url_transfer_set_handler (transfer, handler, data, destroy);
233   if (upload_func != NULL)
234     gsk_url_transfer_set_upload (transfer, upload_func, upload_data, upload_destroy);
235   if (!gsk_url_transfer_start (transfer, error))
236     return FALSE;
237   g_object_unref (transfer);
238   return TRUE;
239 }
240 
241 static gboolean
handle_timeout(gpointer data)242 handle_timeout (gpointer data)
243 {
244   GskUrlTransfer *transfer = GSK_URL_TRANSFER (data);
245   GskUrlTransferClass *class = GSK_URL_TRANSFER_GET_CLASS (transfer);
246   g_return_val_if_fail (transfer->transfer_state == GSK_URL_TRANSFER_STATE_STARTED, FALSE);
247   transfer->timeout_source = NULL;
248   transfer->timed_out = TRUE;
249 
250   /* hold a reference to transfer temporarily to ensure
251      that the transfer doesn't die in the middle */
252   g_object_ref (transfer);
253   class->timed_out (transfer);
254   g_object_unref (transfer); /* transfer may now be dead */
255   return FALSE;
256 }
257 
258 /**
259  * gsk_url_transfer_start:
260  * @transfer: the Transfer to affect.
261  * @error: place to put the error if anything goes wrong.
262  *
263  * Begin the upload and/or download.  (Maybe start with name-lookup).
264  *
265  * returns: whether the transfer started successfully.
266  * If it returns TRUE, you are guaranteed to receive your
267  * done-notification.  If is returns FALSE, you will definitely not
268  * receive done-notification.
269  */
270 gboolean
gsk_url_transfer_start(GskUrlTransfer * transfer,GError ** error)271 gsk_url_transfer_start      (GskUrlTransfer     *transfer,
272                              GError            **error)
273 {
274   GskUrlTransferClass *class = GSK_URL_TRANSFER_GET_CLASS (transfer);
275   g_assert (class->start != NULL);
276   g_return_val_if_fail (transfer->transfer_state == GSK_URL_TRANSFER_STATE_CONSTRUCTING, FALSE);
277   g_object_ref (transfer);
278   transfer->transfer_state = GSK_URL_TRANSFER_STATE_STARTED;
279   if (!class->start (transfer, error))
280     {
281       transfer->transfer_state = GSK_URL_TRANSFER_STATE_ERROR;
282       g_object_unref (transfer);
283       return FALSE;
284     }
285   if (transfer->has_timeout
286    && transfer->transfer_state == GSK_URL_TRANSFER_STATE_STARTED)
287     {
288       transfer->timeout_source = gsk_main_loop_add_timer (gsk_main_loop_default (),
289                                                           handle_timeout,
290                                                           transfer,
291                                                           NULL,
292                                                           transfer->timeout_ms,
293                                                           -1);
294     }
295   return TRUE;
296 }
297 
298 /**
299  * gsk_url_transfer_set_handler:
300  * @transfer: the Transfer to affect.
301  * @handler: function to be called with the transfer request is
302  * done.  (The transfer content itself is just provided as a stream
303  * though-- only after reading the stream is the transfer truly done)
304  * This function may also be called in a number of error cases.
305  * @data: data to pass to the handler function.
306  * @destroy: function to call when you are done with data.
307  *
308  * The handler/data/destroy triple is used for result notification.
309  * handler() is always invoked exactly once.  To find out how things
310  * went, the handler() should almost always start by
311  * examining transfer->result.
312  */
313 void
gsk_url_transfer_set_handler(GskUrlTransfer * transfer,GskUrlTransferFunc handler,gpointer data,GDestroyNotify destroy)314 gsk_url_transfer_set_handler(GskUrlTransfer     *transfer,
315                              GskUrlTransferFunc  handler,
316                              gpointer            data,
317                              GDestroyNotify      destroy)
318 {
319   g_return_if_fail (transfer->transfer_state == GSK_URL_TRANSFER_STATE_CONSTRUCTING);
320   g_return_if_fail (transfer->handler == NULL);
321   transfer->handler = handler;
322   transfer->handler_data = data;
323   transfer->handler_data_destroy = destroy;
324 }
325 
326 /**
327  * gsk_url_transfer_set_url:
328  * @transfer: the Transfer to affect.
329  * @url: the URL to which to upload or from which to download data.
330  *
331  * Set the URL that is the target of this transfer.
332  * This can only be done once, before the transfer
333  * is started.
334  *
335  * You seldom need to use this function, as it
336  * is called by gsk_url_transfer_new().
337  */
338 void
gsk_url_transfer_set_url(GskUrlTransfer * transfer,GskUrl * url)339 gsk_url_transfer_set_url    (GskUrlTransfer     *transfer,
340                              GskUrl             *url)
341 {
342   g_return_if_fail (transfer->transfer_state == GSK_URL_TRANSFER_STATE_CONSTRUCTING);
343   g_return_if_fail (transfer->url == NULL);
344   g_return_if_fail (GSK_IS_URL (url));
345   transfer->url = g_object_ref (url);
346 }
347 
348 /**
349  * gsk_url_transfer_set_timeout:
350  * @transfer: the Transfer to affect.
351  * @millis: milliseconds to wait before aborting the transfer.
352  *
353  * Set the timeout on the download.
354  *
355  * This can be used to avoid hanging on slow servers.
356  *
357  * This must be called before the transfer is started
358  * (with gsk_url_transfer_start).
359  */
360 void
gsk_url_transfer_set_timeout(GskUrlTransfer * transfer,guint millis)361 gsk_url_transfer_set_timeout(GskUrlTransfer     *transfer,
362                              guint               millis)
363 {
364   g_return_if_fail (transfer->transfer_state == GSK_URL_TRANSFER_STATE_CONSTRUCTING);
365   transfer->has_timeout = 1;
366   transfer->timeout_ms = millis;
367 }
368 
369 /**
370  * gsk_url_transfer_clear_timeout:
371  * @transfer: the Transfer to affect.
372  *
373  * Clear the timeout on the download.
374  *
375  * This must be called before the transfer is started
376  * (with gsk_url_transfer_start).
377  */
378 void
gsk_url_transfer_clear_timeout(GskUrlTransfer * transfer)379 gsk_url_transfer_clear_timeout(GskUrlTransfer     *transfer)
380 {
381   g_return_if_fail (transfer->transfer_state == GSK_URL_TRANSFER_STATE_CONSTRUCTING);
382   transfer->has_timeout = 0;
383 }
384 
385 /**
386  * gsk_url_transfer_set_follow_redirects:
387  * @transfer: the Transfer to affect.
388  * @follow_redirs: whether to follow redirect responses.
389  *
390  * Configure how the transfer will behave when it encounters
391  * redirection responses.
392  *
393  * The default behavior is to follow redirects,
394  * adding them to the list of redirects, but not notifying the
395  * user until we reach a real page (or error).
396  *
397  * If follow_redirects is FALSE, then we are done
398  * even if the download led to a redirect.
399  */
400 void
gsk_url_transfer_set_follow_redirects(GskUrlTransfer * transfer,gboolean follow_redirs)401 gsk_url_transfer_set_follow_redirects(GskUrlTransfer     *transfer,
402                                       gboolean            follow_redirs)
403 {
404   g_return_if_fail (transfer->transfer_state == GSK_URL_TRANSFER_STATE_CONSTRUCTING);
405   transfer->follow_redirects = follow_redirs ? 1 : 0;
406 }
407 
408 
409 /**
410  * gsk_url_transfer_set_address_hint:
411  * @transfer: the Transfer to affect.
412  * @address: the socket-address to use for connecting,
413  * possibly with the wrong port (the port will be overridden by
414  * the URL's port).
415  *
416  * To avoid DNS lookups in very bulky transfer situations,
417  * DNS may be bypassed and replaced with this address.
418  *
419  * Chances are, you want to suppress redirects to:
420  * otherwise, DNS may be used on the redirected URLs.
421  */
422 void
gsk_url_transfer_set_address_hint(GskUrlTransfer * transfer,GskSocketAddress * address)423 gsk_url_transfer_set_address_hint (GskUrlTransfer *transfer,
424                                    GskSocketAddress *address)
425 {
426   g_return_if_fail (transfer->transfer_state == GSK_URL_TRANSFER_STATE_CONSTRUCTING);
427   g_return_if_fail (transfer->address_hint == NULL);
428   transfer->address_hint = g_object_ref (address);
429 }
430 
431 
432 /**
433  * gsk_url_transfer_set_upload:
434  * @transfer: the Transfer to affect.
435  * @func: function that can create the upload's content
436  * as a #GskStream.
437  * @data: data which can be used by the upload function.
438  * @destroy: optional function that will be notified when upload()
439  * will no longer be called (note that the streams it created may
440  * still be extant though).
441  *
442  * Set the upload stream as generally as possible.
443  * Actually you must provide a function
444  * that can make an upload stream on demand--
445  * this is necessary to get redirects right.
446  *
447  * The destroy() function will be called after no more upload-streams
448  * need to be created-- it is quite possible that not all upload-streams
449  * have been finalized by the time the destroy() is invoked.
450  *
451  * If you don't care about redirects, you can
452  * use gsk_url_transfer_set_oneshot_upload().
453  *
454  * If you have a slab of memory that you want to use as the upload stream,
455  * consider using gsk_url_transfer_set_upload_packet().
456  */
457 void
gsk_url_transfer_set_upload(GskUrlTransfer * transfer,GskUrlUploadFunc func,gpointer data,GDestroyNotify destroy)458 gsk_url_transfer_set_upload (GskUrlTransfer     *transfer,
459                              GskUrlUploadFunc    func,
460                              gpointer            data,
461                              GDestroyNotify      destroy)
462 {
463   g_return_if_fail (transfer->transfer_state == GSK_URL_TRANSFER_STATE_CONSTRUCTING);
464   g_return_if_fail (transfer->upload_func == NULL);
465   g_return_if_fail (func != NULL);
466   transfer->upload_func = func;
467   transfer->upload_data = data;
468   transfer->upload_destroy = destroy;
469 }
470 
471 /**
472  * gsk_url_transfer_set_upload_packet:
473  * @transfer: the Transfer to affect.
474  * @packet: the GskPacket containing the upload content as data.
475  *
476  * Set the upload stream in an easy, reliable way using a GskPacket.
477  */
478 static GskStream *
make_packet_into_stream(gpointer data,gssize * size_out,GError ** error)479 make_packet_into_stream (gpointer data,
480                          gssize  *size_out,
481                          GError **error)
482 {
483   GskPacket *packet = data;
484   GskStream *rv = gsk_memory_slab_source_new (packet->data, packet->len,
485                                               (GDestroyNotify) gsk_packet_unref,
486                                               gsk_packet_ref (packet));
487   *size_out = packet->len;
488   return rv;
489 }
490 
491 void
gsk_url_transfer_set_upload_packet(GskUrlTransfer * transfer,GskPacket * packet)492 gsk_url_transfer_set_upload_packet (GskUrlTransfer *transfer,
493                                     GskPacket      *packet)
494 {
495   gsk_url_transfer_set_upload (transfer,
496                                make_packet_into_stream,
497                                gsk_packet_ref (packet),
498                                (GDestroyNotify) gsk_packet_unref);
499 }
500 
501 /**
502  * gsk_url_transfer_set_oneshot_upload:
503  * @transfer: the Transfer to affect.
504  * @size: the length of the stream in bytes, or -1 if you don't know.
505  * @stream: the upload content stream.
506  *
507  * Set the content to upload to the remote URL,
508  * as a #GskStream.
509  *
510  * Since streams can only be read once,
511  * this method only works on URLs that do not require
512  * redirection.
513  */
514 typedef struct
515 {
516   GskStream *stream;
517   gssize size;
518 } ReturnStreamOnce;
519 
520 static GskStream *
return_stream_once(gpointer data,gssize * size_out,GError ** error)521 return_stream_once      (gpointer data,
522                          gssize  *size_out,
523                          GError **error)
524 {
525   ReturnStreamOnce *once = data;
526   GskStream *rv;
527   if (once->stream == NULL)
528     {
529       g_set_error (error,
530                    GSK_G_ERROR_DOMAIN,
531                    GSK_ERROR_TOO_MANY_LINKS,
532                    "one-shot upload transfer was redirected: cannot re-upload data");
533       return NULL;
534     }
535   rv = once->stream;
536   once->stream = NULL;
537   *size_out = once->size;
538   return rv;
539 }
540 static void
destroy_return_stream_once(gpointer data)541 destroy_return_stream_once (gpointer data)
542 {
543   ReturnStreamOnce *once = data;
544   if (once->stream)
545     g_object_unref (once->stream);
546   g_free (once);
547 }
548 
549 void
gsk_url_transfer_set_oneshot_upload(GskUrlTransfer * transfer,GskStream * stream,gssize size)550 gsk_url_transfer_set_oneshot_upload (GskUrlTransfer *transfer,
551                                      GskStream      *stream,
552                                      gssize          size)
553 {
554   ReturnStreamOnce *once;
555   g_return_if_fail (GSK_IS_STREAM (stream));
556   once = g_new (ReturnStreamOnce, 1);
557   once->stream = g_object_ref (stream);
558   once->size = size;
559   gsk_url_transfer_set_upload (transfer,
560                                return_stream_once,
561                                once,
562                                destroy_return_stream_once);
563 }
564 
565 /**
566  * gsk_url_transfer_cancel:
567  * @transfer: the Transfer to affect.
568  *
569  * Abort a running transfer.
570  *
571  * If you registered a handler, it will be called with
572  * result GSK_URL_TRANSFER_CANCELLED.
573  */
574 void
gsk_url_transfer_cancel(GskUrlTransfer * transfer)575 gsk_url_transfer_cancel     (GskUrlTransfer     *transfer)
576 {
577   GskUrlTransferClass *class = GSK_URL_TRANSFER_GET_CLASS (transfer);
578   g_return_if_fail (transfer->transfer_state == GSK_URL_TRANSFER_STATE_STARTED);
579   if (class->cancel == NULL)
580     {
581       g_warning ("%s does not implement cancel()!", G_OBJECT_CLASS_NAME (class));
582       return;
583     }
584   class->cancel (transfer);
585 }
586 
587 /* --- Protected API --- */
588 /**
589  * gsk_url_transfer_has_upload:
590  * @transfer: the Transfer to query.
591  *
592  * Figure out whether this transfer has upload data.
593  *
594  * This function should only be needed by implementors
595  * of types of GskUrlTransfer.
596  *
597  * returns: whether the transfer has upload data.
598  */
599 gboolean
gsk_url_transfer_has_upload(GskUrlTransfer * transfer)600 gsk_url_transfer_has_upload      (GskUrlTransfer     *transfer)
601 {
602   return transfer->upload_func != NULL;
603 }
604 
605 /**
606  * gsk_url_transfer_create_upload:
607  * @transfer: the Transfer to use.
608  * @size_out: the size of the stream in bytes, or -1 if the size is unknown.
609  * @error: optional location to store the #GError if there is a problem.
610  *
611  * Create a upload stream for this transfer based on the user's creator
612  * function.
613  *
614  * This function should only be needed by implementors
615  * of types of GskUrlTransfer.
616  *
617  * returns: a newly allocated #GskStream, or NULL if an error occurs.
618  */
619 GskStream *
gsk_url_transfer_create_upload(GskUrlTransfer * transfer,gssize * size_out,GError ** error)620 gsk_url_transfer_create_upload   (GskUrlTransfer     *transfer,
621                                   gssize             *size_out,
622                                   GError            **error)
623 {
624   g_return_val_if_fail (transfer->upload_func != NULL, NULL);
625   *size_out = -1;
626   return transfer->upload_func (transfer->upload_data, size_out, error);
627 }
628 
629 /**
630  * gsk_url_transfer_peek_expects_download_stream:
631  * @transfer: the Transfer to use.
632  * returns: whether this transfer has a download handler.
633  *
634  * This function can be used to see if download-content is expected.
635  *
636  * This function should only be needed by implementors
637  * of types of GskUrlTransfer.
638  */
639 gboolean
gsk_url_transfer_peek_expects_download_stream(GskUrlTransfer * transfer)640 gsk_url_transfer_peek_expects_download_stream (GskUrlTransfer *transfer)
641 {
642   g_return_val_if_fail (transfer->transfer_state == GSK_URL_TRANSFER_STATE_STARTED, FALSE);
643   return transfer->handler != NULL;
644 }
645 
646 /**
647  * gsk_url_transfer_set_address:
648  * @transfer: the Transfer to affect.
649  * @addr: the address of the host whose lookup was completed.
650  *
651  * Set the socket-address for informational purposes.
652  * This is occasionally interesting to the user of the Transfer.
653  *
654  * This function should only be needed by implementors
655  * of types of GskUrlTransfer.
656  */
657 void
gsk_url_transfer_set_address(GskUrlTransfer * transfer,GskSocketAddress * addr)658 gsk_url_transfer_set_address     (GskUrlTransfer     *transfer,
659                                   GskSocketAddress   *addr)
660 {
661   g_object_ref (addr);
662   if (transfer->address)
663     g_object_unref (transfer->address);
664   transfer->address = addr;
665 }
666 
667 static inline gboolean
strings_equal(const char * a,const char * b)668 strings_equal (const char *a, const char *b)
669 {
670   if (a == NULL)
671     return b == NULL;
672   else if (b == NULL)
673     return FALSE;
674   else
675     return strcmp (a, b) == 0;
676 }
677 
678 static gboolean
urls_equal_up_to_fragment(const GskUrl * a,const GskUrl * b)679 urls_equal_up_to_fragment (const GskUrl *a,
680                            const GskUrl *b)
681 {
682   return a->scheme == b->scheme
683       && strings_equal (a->host, b->host)
684       && strings_equal (a->password, b->password)
685       && gsk_url_get_port (a) == gsk_url_get_port (b)
686       && strings_equal (a->user_name, b->user_name)
687       && strings_equal (a->path, b->path)
688       && strings_equal (a->query, b->query);
689 }
690 
691 /**
692  * gsk_url_transfer_add_redirect:
693  * @transfer: the Transfer to affect.
694  * @request: request object for this segment of the transfer.
695  * @response: response object for this segment of the transfer.
696  * @is_permanent: whether the content is permanently relocated to this address.
697  * @dest_url: the URL to which we have been redirected.
698  *
699  * Add an entry to the list of redirects
700  * that we have encountered while trying to
701  * service this request.
702  *
703  * Most users of GskUrlTransfer won't care about these redirects--
704  * they are provided to the rare client that cares about the redirect-path.
705  * More commonly, users merely wish to suppress redirect handling: that can be done
706  * more easily by gsk_url_transfer_set_follow_redirects().
707  *
708  * This function should only be needed by implementors
709  * of types of GskUrlTransfer.
710  *
711  * returns: whether the redirect was allowed (it is disallowed if
712  * it is a circular redirect. In that case, we will set 'transfer->error',
713  * and call gsk_url_transfer_notify_done().
714  */
715 gboolean
gsk_url_transfer_add_redirect(GskUrlTransfer * transfer,GObject * request,GObject * response,gboolean is_permanent,GskUrl * dest_url)716 gsk_url_transfer_add_redirect    (GskUrlTransfer     *transfer,
717                                   GObject            *request,
718                                   GObject            *response,
719                                   gboolean            is_permanent,
720                                   GskUrl             *dest_url)
721 {
722   GskUrlTransferRedirect *redirect;
723   g_return_val_if_fail (transfer->transfer_state == GSK_URL_TRANSFER_STATE_STARTED, TRUE);
724   g_return_val_if_fail (GSK_IS_URL (dest_url), TRUE);
725 
726   /* Detect circular references. */
727   if (urls_equal_up_to_fragment (dest_url, transfer->url))
728     goto circular_redirect;
729   for (redirect = transfer->first_redirect; redirect != NULL; redirect = redirect->next)
730     if (urls_equal_up_to_fragment (redirect->url, dest_url))
731       goto circular_redirect;
732 
733   redirect = g_new (GskUrlTransferRedirect, 1);
734   redirect->is_permanent = is_permanent;
735   redirect->url = g_object_ref (dest_url);
736   redirect->request = request ? g_object_ref (request) : transfer->request ? g_object_ref (transfer->request) : NULL;
737   redirect->response = response ? g_object_ref (response) : NULL;
738   redirect->next = NULL;
739 
740   if (transfer->first_redirect == NULL)
741     transfer->first_redirect = redirect;
742   else
743     transfer->last_redirect->next = redirect;
744   transfer->last_redirect = redirect;
745 
746   transfer->redirect_is_permanent = is_permanent;
747   transfer->redirect_url = dest_url;
748   return TRUE;
749 
750 
751 circular_redirect:
752   gsk_url_transfer_take_error (transfer,
753                                g_error_new (GSK_G_ERROR_DOMAIN,
754                                             GSK_ERROR_CIRCULAR,
755                                             "circular redirects encountered"));
756   gsk_url_transfer_notify_done (transfer, GSK_URL_TRANSFER_ERROR_REDIRECT_LOOP);
757   return FALSE;
758 }
759 
760 /**
761  * gsk_url_transfer_set_download:
762  * @transfer: the Transfer to affect.
763  * @content: the content-stream for the downloaded data.
764  *
765  * Set the incoming-content that is associated with this transfer.
766  * This will used by the user of the Transfer.
767  *
768  * This function should only be needed by implementors
769  * of types of GskUrlTransfer.
770  */
771 void
gsk_url_transfer_set_download(GskUrlTransfer * transfer,GskStream * content)772 gsk_url_transfer_set_download    (GskUrlTransfer     *transfer,
773                                   GskStream          *content)
774 {
775   g_return_if_fail (transfer->transfer_state == GSK_URL_TRANSFER_STATE_STARTED);
776   g_return_if_fail (transfer->content == NULL);
777   g_return_if_fail (GSK_IS_STREAM (content));
778   transfer->content = g_object_ref (content);
779 }
780 
781 /**
782  * gsk_url_transfer_set_request:
783  * @transfer: the Transfer to affect.
784  * @request: the request object to store in the transfer information.
785  *
786  * Set the outgoing-request header data for this transaction.
787  *
788  * This function should only be needed by implementors
789  * of types of GskUrlTransfer.
790  */
791 void
gsk_url_transfer_set_request(GskUrlTransfer * transfer,GObject * request)792 gsk_url_transfer_set_request     (GskUrlTransfer     *transfer,
793                                   GObject            *request)
794 {
795   GObject *old_request = transfer->request;
796   g_return_if_fail (transfer->transfer_state == GSK_URL_TRANSFER_STATE_STARTED);
797   g_return_if_fail (G_IS_OBJECT (request));
798   transfer->request = g_object_ref (request);
799   if (old_request)
800     g_object_unref (old_request);
801 }
802 
803 /**
804  * gsk_url_transfer_set_response:
805  * @transfer: the Transfer to affect.
806  * @response: the response object to store in the transfer information.
807  *
808  * Set the incoming-response header data for this transaction.
809  *
810  * This function should only be needed by implementors
811  * of types of GskUrlTransfer.
812  */
813 void
gsk_url_transfer_set_response(GskUrlTransfer * transfer,GObject * response)814 gsk_url_transfer_set_response    (GskUrlTransfer     *transfer,
815                                   GObject            *response)
816 {
817   GObject *old_response = transfer->response;
818   g_return_if_fail (transfer->transfer_state == GSK_URL_TRANSFER_STATE_STARTED);
819   g_return_if_fail (transfer->response == NULL);
820   transfer->response = g_object_ref (response);
821   if (old_response)
822     g_object_unref (old_response);
823 }
824 
825 /**
826  * gsk_url_transfer_set_error:
827  * @transfer: the Transfer to affect.
828  * @error: the error to associate with the transfer.
829  *
830  * Set the error field for this transaction.
831  * A copy of the error parameter is made.
832  *
833  * This function should only be needed by implementors
834  * of types of GskUrlTransfer.
835  */
836 void
gsk_url_transfer_set_error(GskUrlTransfer * transfer,const GError * error)837 gsk_url_transfer_set_error       (GskUrlTransfer     *transfer,
838                                   const GError       *error)
839 {
840   GError *copy = g_error_copy (error);
841   g_return_if_fail (error != NULL);
842   if (transfer->error)
843     g_error_free (transfer->error);
844   transfer->error = copy;
845 }
846 
847 /**
848  * gsk_url_transfer_take_error:
849  * @transfer: the Transfer to affect.
850  * @error: the error to associate with the transfer.
851  *
852  * Set the error field for this transaction.
853  * The error parameter will be freed eventually by the
854  * #GskUrlTransfer.
855  *
856  * This function should only be needed by implementors
857  * of types of GskUrlTransfer.
858  */
859 void
gsk_url_transfer_take_error(GskUrlTransfer * transfer,GError * error)860 gsk_url_transfer_take_error      (GskUrlTransfer     *transfer,
861                                   GError             *error)
862 {
863   g_return_if_fail (error != NULL);
864   if (error == transfer->error)
865     return;
866   if (transfer->error)
867     g_error_free (transfer->error);
868   transfer->error = error;
869 }
870 
871 /**
872  * gsk_url_transfer_is_done:
873  * @transfer: the Transfer to query.
874  *
875  * Find out whether the transfer is done.
876  * The transfer is done iff the callback has been invoked.
877  *
878  * returns: whether the function is done.
879  */
880 gboolean
gsk_url_transfer_is_done(GskUrlTransfer * transfer)881 gsk_url_transfer_is_done (GskUrlTransfer *transfer)
882 {
883   return (transfer->transfer_state == GSK_URL_TRANSFER_STATE_DONE);
884 }
885 
886 /**
887  * gsk_url_transfer_notify_done:
888  * @transfer: the Transfer to affect.
889  * @result: the transfer's result status code.
890  *
891  * Transition the transfer to the DONE state,
892  * and invoke the user's callback (if any).
893  * This function may only be invoked once per transfer.
894  *
895  * This function should only be needed by implementors
896  * of types of GskUrlTransfer.
897  */
898 void
gsk_url_transfer_notify_done(GskUrlTransfer * transfer,GskUrlTransferResult result)899 gsk_url_transfer_notify_done     (GskUrlTransfer     *transfer,
900                                   GskUrlTransferResult result)
901 {
902   g_assert (transfer->transfer_state == GSK_URL_TRANSFER_STATE_STARTED);
903   transfer->transfer_state = GSK_URL_TRANSFER_STATE_DONE;
904   transfer->result = result;
905 
906   if (transfer->timeout_source)
907     {
908       GskSource *timeout = transfer->timeout_source;
909       transfer->timeout_source = NULL;
910       gsk_source_remove (timeout);
911     }
912 
913   if (transfer->handler != NULL)
914     transfer->handler (transfer, transfer->handler_data);
915 
916   /* we must relinquish these, or else there will circular ref-count leaks
917      if the user tries to do tricks like the above commented code. */
918   if (transfer->content != NULL)
919     {
920       GskStream *tmp = transfer->content;
921       transfer->content = NULL;
922       g_object_unref (tmp);
923     }
924   if (transfer->upload_func != NULL)
925     {
926       gpointer data = transfer->upload_data;
927       GDestroyNotify destroy = transfer->upload_destroy;
928       transfer->upload_func = NULL;
929       transfer->upload_data = NULL;
930       transfer->upload_destroy = NULL;
931       if (destroy)
932         destroy (data);
933     }
934 
935   if (transfer->handler_data_destroy)
936     transfer->handler_data_destroy (transfer->handler_data);
937 
938   transfer->handler = NULL;
939   transfer->handler_data_destroy = NULL;
940 
941   g_object_unref (transfer);
942 }
943 
944 /* Registering a transfer type */
945 static GHashTable *scheme_to_slist_of_classes = NULL;
946 /**
947  * gsk_url_transfer_class_register:
948  * @scheme: the URL scheme that this class of transfer can handle.
949  * @transfer_class: the class that can handle the URL type.
950  *
951  * Register a class of URL transfer that can
952  * handle a given scheme.
953  * It will only be instantiated if the class' test method
954  * returns TRUE, to indicate that it can handle the specific URL.
955  */
956 void
gsk_url_transfer_class_register(GskUrlScheme scheme,GskUrlTransferClass * transfer_class)957 gsk_url_transfer_class_register  (GskUrlScheme            scheme,
958                                   GskUrlTransferClass    *transfer_class)
959 {
960   GSList *list;
961   if (scheme_to_slist_of_classes == NULL)
962     scheme_to_slist_of_classes = g_hash_table_new (NULL, NULL);
963   list = g_hash_table_lookup (scheme_to_slist_of_classes, GUINT_TO_POINTER (scheme));
964   if (list == NULL)
965     {
966       list = g_slist_prepend (NULL, transfer_class);
967       g_hash_table_insert (scheme_to_slist_of_classes, GUINT_TO_POINTER (scheme), list);
968     }
969   else
970     list = g_slist_append (list, transfer_class);
971 }
972 
973 /**
974  * gsk_url_transfer_new:
975  * @url: the URL to create a transfer object for.
976  *
977  * Create a URL transfer of the appropriate type for the given URL.
978  * We try the registered classes, in order.
979  *
980  * returns: a newly allocated Transfer object, or NULL if no transfer-class
981  * could handle the URL.
982  */
983 GskUrlTransfer *
gsk_url_transfer_new(GskUrl * url)984 gsk_url_transfer_new             (GskUrl             *url)
985 {
986   GSList *list = g_hash_table_lookup (scheme_to_slist_of_classes, GUINT_TO_POINTER (url->scheme));
987   while (list != NULL)
988     {
989       GskUrlTransferClass *class = GSK_URL_TRANSFER_CLASS (list->data);
990       if (class->test == NULL || class->test (class, url))
991         {
992           GskUrlTransfer *transfer = g_object_new (G_OBJECT_CLASS_TYPE (class), NULL);
993           gsk_url_transfer_set_url (transfer, url);
994           return transfer;
995         }
996       list = list->next;
997     }
998   return NULL;
999 }
1000 
1001 /**
1002  * gsk_url_transfer_get_state_string:
1003  * @transfer: the transfer to describe.
1004  *
1005  * Get a newly allocated, human-readable description
1006  * of the state of the transfer.
1007  *
1008  * returns: the newly-allocated string.
1009  */
1010 char *
gsk_url_transfer_get_state_string(GskUrlTransfer * transfer)1011 gsk_url_transfer_get_state_string (GskUrlTransfer *transfer)
1012 {
1013   GskUrlTransferClass *class = GSK_URL_TRANSFER_GET_CLASS (transfer);
1014   switch (transfer->transfer_state)
1015     {
1016     case GSK_URL_TRANSFER_STATE_CONSTRUCTING:
1017       return class->get_constructing_state (transfer);
1018     case GSK_URL_TRANSFER_STATE_STARTED:
1019       return class->get_running_state (transfer);
1020     case GSK_URL_TRANSFER_STATE_DONE:
1021       return class->get_done_state (transfer);
1022     default:
1023       return g_strdup ("gsk_url_transfer_get_state_string: INVALID state");
1024     }
1025 }
1026 
1027 
1028 /* --- convert a transfer to a stream --- */
1029 GType gsk_url_transfer_stream_get_type(void) G_GNUC_CONST;
1030 #define GSK_TYPE_URL_TRANSFER_STREAM              (gsk_url_transfer_stream_get_type ())
1031 #define GSK_URL_TRANSFER_STREAM(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_URL_TRANSFER_STREAM, GskUrlTransferStream))
1032 #define GSK_URL_TRANSFER_STREAM_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_URL_TRANSFER_STREAM, GskUrlTransferStreamClass))
1033 #define GSK_URL_TRANSFER_STREAM_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_URL_TRANSFER_STREAM, GskUrlTransferStreamClass))
1034 #define GSK_IS_URL_TRANSFER_STREAM(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_URL_TRANSFER_STREAM))
1035 #define GSK_IS_URL_TRANSFER_STREAM_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_URL_TRANSFER_STREAM))
1036 typedef struct _UfUrlTransferStreamClass GskUrlTransferStreamClass;
1037 typedef struct _UfUrlTransferStream GskUrlTransferStream;
1038 struct _UfUrlTransferStreamClass
1039 {
1040   GskStreamClass base_class;
1041 };
1042 struct _UfUrlTransferStream
1043 {
1044   GskStream base_instance;
1045   GskUrlTransfer *transfer;
1046   GskStream *substream;
1047 };
1048 
1049 G_DEFINE_TYPE(GskUrlTransferStream, gsk_url_transfer_stream, GSK_TYPE_STREAM);
1050 
1051 static void
gsk_url_transfer_stream_finalize(GObject * object)1052 gsk_url_transfer_stream_finalize (GObject *object)
1053 {
1054   GskUrlTransferStream *transfer_stream = GSK_URL_TRANSFER_STREAM (object);
1055   g_assert (transfer_stream->transfer == NULL);
1056   if (transfer_stream->substream)
1057     {
1058       gsk_io_untrap_readable (transfer_stream->substream);
1059       g_object_unref (transfer_stream->substream);
1060     }
1061   G_OBJECT_CLASS (gsk_url_transfer_stream_parent_class)->finalize (object);
1062 }
1063 static gboolean
handle_substream_is_readable(GskIO * io,gpointer data)1064 handle_substream_is_readable (GskIO *io, gpointer data)
1065 {
1066   gsk_io_notify_ready_to_read (data);
1067   return TRUE;
1068 }
1069 static gboolean
handle_substream_read_shutdown(GskIO * io,gpointer data)1070 handle_substream_read_shutdown (GskIO *io, gpointer data)
1071 {
1072   GskUrlTransferStream *transfer_stream = GSK_URL_TRANSFER_STREAM (data);
1073   gsk_io_notify_read_shutdown (GSK_IO (transfer_stream));
1074   if (transfer_stream->substream)
1075     {
1076       gsk_io_untrap_readable (transfer_stream->substream);
1077       g_object_unref (transfer_stream->substream);
1078       transfer_stream->substream = NULL;
1079     }
1080   return FALSE;
1081 }
1082 
1083 static void
gsk_url_transfer_stream_set_poll_read(GskIO * io,gboolean do_poll)1084 gsk_url_transfer_stream_set_poll_read   (GskIO      *io,
1085 				        gboolean    do_poll)
1086 {
1087   GskUrlTransferStream *transfer_stream = GSK_URL_TRANSFER_STREAM (io);
1088   if (transfer_stream->substream == NULL)
1089     return;
1090   if (do_poll)
1091     gsk_io_trap_readable (transfer_stream->substream,
1092                           handle_substream_is_readable,
1093                           handle_substream_read_shutdown,
1094                           transfer_stream,
1095                           NULL);
1096   else
1097     gsk_io_untrap_readable (transfer_stream->substream);
1098 }
1099 
1100 static gboolean
gsk_url_transfer_stream_shutdown_read(GskIO * io,GError ** error)1101 gsk_url_transfer_stream_shutdown_read   (GskIO      *io,
1102                                         GError    **error)
1103 {
1104   GskUrlTransferStream *transfer_stream = GSK_URL_TRANSFER_STREAM (io);
1105   if (transfer_stream->transfer != NULL)
1106     gsk_url_transfer_cancel (transfer_stream->transfer);
1107   if (transfer_stream->substream != NULL)
1108     gsk_io_read_shutdown (GSK_IO (transfer_stream->substream), NULL);
1109   return TRUE;
1110 }
1111 
1112 static guint
gsk_url_transfer_stream_raw_read(GskStream * stream,gpointer data,guint length,GError ** error)1113 gsk_url_transfer_stream_raw_read (GskStream     *stream,
1114 			 	 gpointer       data,
1115 			 	 guint          length,
1116 			 	 GError       **error)
1117 {
1118   GskUrlTransferStream *transfer_stream = GSK_URL_TRANSFER_STREAM (stream);
1119   if (transfer_stream->substream == NULL)
1120     return 0;
1121   return gsk_stream_read (transfer_stream->substream, data, length, error);
1122 }
1123 
1124 static guint
gsk_url_transfer_stream_raw_read_buffer(GskStream * stream,GskBuffer * buffer,GError ** error)1125 gsk_url_transfer_stream_raw_read_buffer (GskStream     *stream,
1126 				        GskBuffer     *buffer,
1127 				        GError       **error)
1128 {
1129   GskUrlTransferStream *transfer_stream = GSK_URL_TRANSFER_STREAM (stream);
1130   if (transfer_stream->substream == NULL)
1131     return 0;
1132   return gsk_stream_read_buffer (transfer_stream->substream, buffer, error);
1133 }
1134 
1135 static void
gsk_url_transfer_stream_class_init(GskUrlTransferStreamClass * class)1136 gsk_url_transfer_stream_class_init (GskUrlTransferStreamClass *class)
1137 {
1138   GskIOClass *io_class = GSK_IO_CLASS (class);
1139   GskStreamClass *stream_class = GSK_STREAM_CLASS (class);
1140   GObjectClass *object_class = G_OBJECT_CLASS (class);
1141   stream_class->raw_read = gsk_url_transfer_stream_raw_read;
1142   stream_class->raw_read_buffer = gsk_url_transfer_stream_raw_read_buffer;
1143   io_class->set_poll_read = gsk_url_transfer_stream_set_poll_read;
1144   io_class->shutdown_read = gsk_url_transfer_stream_shutdown_read;
1145   object_class->finalize = gsk_url_transfer_stream_finalize;
1146 }
1147 
1148 static void
gsk_url_transfer_stream_init(GskUrlTransferStream * transfer_stream)1149 gsk_url_transfer_stream_init (GskUrlTransferStream *transfer_stream)
1150 {
1151   gsk_stream_mark_is_readable (transfer_stream);
1152 }
1153 
1154 static void
handle_transfer_done(GskUrlTransfer * transfer,gpointer data)1155 handle_transfer_done (GskUrlTransfer *transfer,
1156                       gpointer        data)
1157 {
1158   GskUrlTransferStream *transfer_stream = GSK_URL_TRANSFER_STREAM (data);
1159   g_assert (transfer_stream->transfer == transfer);
1160   transfer_stream->transfer = NULL;
1161 
1162   if (transfer->error != NULL)
1163     gsk_io_set_gerror (GSK_IO (transfer_stream), GSK_IO_ERROR_CONNECT,
1164                        g_error_copy (transfer->error));
1165   if (transfer->content != NULL)
1166     {
1167       transfer_stream->substream = g_object_ref (transfer->content);
1168       if (gsk_io_is_polling_for_read (transfer_stream))
1169         gsk_io_trap_readable (transfer_stream->substream,
1170                               handle_substream_is_readable,
1171                               handle_substream_read_shutdown,
1172                               g_object_ref (transfer_stream),
1173                               g_object_unref);
1174     }
1175   else
1176     {
1177       gsk_io_notify_read_shutdown (GSK_IO (transfer_stream));
1178     }
1179 }
1180 
1181 /**
1182  * gsk_url_transfer_stream_new:
1183  * @transfer: the transfer.  must not be started.
1184  * @error: optional location to store the #GError if there is a problem.
1185  *
1186  * This code will start the transfer,
1187  * and return a stream that you can trap immediately.
1188  *
1189  * returns: the new stream, or NULL if an error occurred.
1190  */
1191 GskStream *
gsk_url_transfer_stream_new(GskUrlTransfer * transfer,GError ** error)1192 gsk_url_transfer_stream_new (GskUrlTransfer *transfer,
1193                              GError        **error)
1194 {
1195   GskUrlTransferStream *transfer_stream = g_object_new (GSK_TYPE_URL_TRANSFER_STREAM, NULL);
1196   transfer_stream->transfer = transfer;
1197   gsk_url_transfer_set_handler (transfer,
1198                                 handle_transfer_done,
1199                                 g_object_ref (transfer_stream),
1200                                 g_object_unref);
1201   if (!gsk_url_transfer_start (transfer, error))
1202     {
1203       transfer_stream->transfer = NULL;
1204       g_object_unref (transfer_stream);
1205       return NULL;
1206     }
1207   return GSK_STREAM (transfer_stream);
1208 }
1209