1 /* NB: the transfer isn't *really* done until you're finishing uploading and/or downloading,
2    but we actually ignore that;  not ignoring makes a slightly irritating circular reference danger.
3  */
4 #ifndef __GSK_URL_TRANSFER_H_
5 #define __GSK_URL_TRANSFER_H_
6 
7 #include "gskurl.h"
8 #include "../gsksocketaddress.h"
9 #include "../gskmainloop.h"
10 #include "../gskpacket.h"
11 
12 G_BEGIN_DECLS
13 
14 typedef struct _GskUrlTransferClass GskUrlTransferClass;
15 typedef struct _GskUrlTransferRedirect GskUrlTransferRedirect;
16 typedef struct _GskUrlTransfer GskUrlTransfer;
17 
18 GType gsk_url_transfer_get_type(void) G_GNUC_CONST;
19 #define GSK_TYPE_URL_TRANSFER			(gsk_url_transfer_get_type ())
20 #define GSK_URL_TRANSFER(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_URL_TRANSFER, GskUrlTransfer))
21 #define GSK_URL_TRANSFER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_URL_TRANSFER, GskUrlTransferClass))
22 #define GSK_URL_TRANSFER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_URL_TRANSFER, GskUrlTransferClass))
23 #define GSK_IS_URL_TRANSFER(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_URL_TRANSFER))
24 #define GSK_IS_URL_TRANSFER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_URL_TRANSFER))
25 
26 typedef enum
27 {
28   GSK_URL_TRANSFER_ERROR_BAD_REQUEST,
29   GSK_URL_TRANSFER_ERROR_BAD_NAME,
30   GSK_URL_TRANSFER_ERROR_NO_SERVER,
31   GSK_URL_TRANSFER_ERROR_NOT_FOUND,
32   GSK_URL_TRANSFER_ERROR_SERVER_ERROR,
33   GSK_URL_TRANSFER_ERROR_UNSUPPORTED,
34   GSK_URL_TRANSFER_ERROR_TIMED_OUT,
35   GSK_URL_TRANSFER_ERROR_REDIRECT_LOOP,
36   GSK_URL_TRANSFER_REDIRECT,
37   GSK_URL_TRANSFER_CANCELLED,
38   GSK_URL_TRANSFER_SUCCESS
39 } GskUrlTransferResult;
40 
41 #define GSK_URL_TRANSFER_N_RESULTS      (GSK_URL_TRANSFER_SUCCESS+1)
42 
43 const char *gsk_url_transfer_result_name (GskUrlTransferResult result);
44 
45 typedef void (*GskUrlTransferFunc)    (GskUrlTransfer *info,
46                                        gpointer        user_data);
47 typedef GskStream *(*GskUrlUploadFunc)(gpointer        upload_data,
48                                        gssize         *size_out,
49                                        GError        **error);
50 
51 struct _GskUrlTransferClass
52 {
53   GObjectClass base_class;
54 
55   /* The test() method is called before the instance
56      is constructed, to give the class an opportunity to
57      see if it can handle the url. */
58   gboolean (*test)  (GskUrlTransferClass *transfer_class,
59                      const GskUrl        *url);
60 
61   /* The start() method is called on an instance which
62      has been configured.  It returns TRUE if the transfer is started.
63      If it returns FALSE, an error has occurred. */
64   gboolean (*start) (GskUrlTransfer      *transfer,
65                      GError             **error);
66 
67   void     (*cancel)(GskUrlTransfer     *transfer);
68 
69   char    *(*get_constructing_state) (GskUrlTransfer *transfer);
70   char    *(*get_running_state) (GskUrlTransfer *transfer);
71   char    *(*get_done_state) (GskUrlTransfer *transfer);
72 
73   /* default impl calls gsk_url_transfer_task_notify_done(ERROR_TIMEOUT) */
74   void     (*timed_out)(GskUrlTransfer     *transfer);
75 };
76 
77 struct _GskUrlTransferRedirect
78 {
79   gboolean is_permanent;
80   GskUrl *url;
81   GObject *request;
82   GObject *response;
83   GskUrlTransferRedirect *next;
84 };
85 
86 
87 
88 struct _GskUrlTransfer
89 {
90   GObject base_instance;
91 
92   /*< public >*/
93   /* --- information prepared for the handler --- */
94   GskUrlTransferResult result;
95   GskUrl *url;
96   GSList *redirect_urls;        // XXX: unused
97   GskUrlTransferRedirect *first_redirect, *last_redirect;
98   GskSocketAddress *address;
99 
100   /* may be available: protocol-specific headers */
101   GObject *request;     /* a GskHttpRequest probably */
102   GObject *response;    /* a GskHttpResponse probably */
103 
104   GskStream *content;   /* the downloading content */
105 
106   /* the last redirect (if any) */
107   GskUrl *redirect_url; /* [just a peeked version of last_redirect->url, not a ref] */
108   gboolean redirect_is_permanent;
109 
110   /* ERROR status codes */
111   GError *error;
112 
113   /*< protected >*/
114   GskSocketAddress   *address_hint;
115   guint               follow_redirects : 1;
116   guint               has_timeout : 1;
117   guint               timed_out : 1;
118 
119   /*< private >*/
120   GskSource *timeout_source;
121   guint timeout_ms;
122 
123   GskUrlTransferFunc handler;
124   gpointer handler_data;
125   GDestroyNotify handler_data_destroy;
126 
127   GskUrlUploadFunc    upload_func;
128   gpointer            upload_data;
129   GDestroyNotify      upload_destroy;
130 
131   guint transfer_state;
132 };
133 
134 gboolean        gsk_url_transfer            (GskUrl            *url,
135                                              GskUrlUploadFunc   upload_func,
136                                              gpointer           upload_data,
137                                              GDestroyNotify     upload_destroy,
138                                              GskUrlTransferFunc handler,
139                                              gpointer           data,
140                                              GDestroyNotify     destroy,
141                                              GError           **error);
142 
143 GskUrlTransfer *gsk_url_transfer_new        (GskUrl             *url);
144 
145 void            gsk_url_transfer_set_handler(GskUrlTransfer     *transfer,
146                                              GskUrlTransferFunc  handler,
147                                              gpointer            data,
148                                              GDestroyNotify      destroy);
149 void            gsk_url_transfer_set_url    (GskUrlTransfer     *transfer,
150                                              GskUrl             *url);
151 void            gsk_url_transfer_set_upload (GskUrlTransfer     *transfer,
152                                              GskUrlUploadFunc    func,
153                                              gpointer            data,
154                                              GDestroyNotify      destroy);
155 void      gsk_url_transfer_set_upload_packet(GskUrlTransfer     *transfer,
156                                              GskPacket          *packet);
157 void     gsk_url_transfer_set_oneshot_upload(GskUrlTransfer     *transfer,
158                                              GskStream          *stream,
159                                              gssize              size);
160 
161 void            gsk_url_transfer_set_timeout(GskUrlTransfer     *transfer,
162                                              guint               millis);
163 void          gsk_url_transfer_clear_timeout(GskUrlTransfer     *transfer);
164 
165 void   gsk_url_transfer_set_follow_redirects(GskUrlTransfer     *transfer,
166                                              gboolean            follow_redirs);
167 void            gsk_url_transfer_set_address_hint(GskUrlTransfer     *transfer,
168                                                   GskSocketAddress   *address);
169 
170 /* Starting a transfer */
171 gboolean        gsk_url_transfer_start      (GskUrlTransfer     *transfer,
172                                              GError            **error);
173 
174 /* Cancelling a started transfer */
175 void            gsk_url_transfer_cancel     (GskUrlTransfer     *transfer);
176 
177 
178 char *          gsk_url_transfer_get_state_string (GskUrlTransfer *transfer);
179 
180 
181 /* --- Treating a Transfer as a Stream --- */
182 GskStream     * gsk_url_transfer_stream_new      (GskUrlTransfer *transfer,
183                                                   GError        **error);
184 
185 /* --- Protected API --- */
186 gboolean        gsk_url_transfer_has_upload      (GskUrlTransfer     *transfer);
187 GskStream      *gsk_url_transfer_create_upload   (GskUrlTransfer     *transfer,
188                                                   gssize             *size_out,
189                                                   GError            **error);
190 gboolean        gsk_url_transfer_peek_expects_download_stream (GskUrlTransfer *transfer);
191 
192 /* whether gsk_url_transfer_notify_done() has been called */
193 gboolean        gsk_url_transfer_is_done         (GskUrlTransfer     *transfer);
194 
195 /* invoke the notification callbacks as needed */
196 void            gsk_url_transfer_set_address     (GskUrlTransfer     *transfer,
197                                                   GskSocketAddress   *addr);
198 gboolean        gsk_url_transfer_add_redirect    (GskUrlTransfer     *transfer,
199                                                   GObject            *request,
200                                                   GObject            *response,
201                                                   gboolean            is_permanent,
202                                                   GskUrl             *dest_url);
203 void            gsk_url_transfer_set_download    (GskUrlTransfer     *transfer,
204                                                   GskStream          *content);
205 void            gsk_url_transfer_set_request     (GskUrlTransfer     *transfer,
206                                                   GObject            *request);
207 void            gsk_url_transfer_set_response    (GskUrlTransfer     *transfer,
208                                                   GObject            *response);
209 
210 void            gsk_url_transfer_set_error       (GskUrlTransfer     *transfer,
211                                                   const GError       *error);
212 void            gsk_url_transfer_take_error      (GskUrlTransfer     *transfer,
213                                                   GError             *error);
214 
215 /* NOTE: does a g_object_unref() (undoing the one in gsk_url_transfer_start),
216    so the transfer may be destroyed by this function. */
217 void            gsk_url_transfer_notify_done     (GskUrlTransfer     *transfer,
218                                                   GskUrlTransferResult result);
219 
220 /* Registering a transfer type */
221 void            gsk_url_transfer_class_register  (GskUrlScheme            scheme,
222                                                   GskUrlTransferClass    *transfer_class);
223 
224 G_END_DECLS
225 
226 #endif
227