GskUrlTransfer

GskUrlTransfer — Transfer data with a location by URL.

Synopsis




            GskUrlTransferRedirect;
enum        GskUrlTransferResult;
#define     GSK_URL_TRANSFER_N_RESULTS
const char* gsk_url_transfer_result_name    (GskUrlTransferResult result);
void        (*GskUrlTransferFunc)           (GskUrlTransfer *info,
                                             gpointer user_data);
GskStream*  (*GskUrlUploadFunc)             (gpointer upload_data,
                                             gssize *size_out,
                                             GError **error);
            GskUrlTransfer;
gboolean    gsk_url_transfer                (GskUrl *url,
                                             GskUrlUploadFunc upload_func,
                                             gpointer upload_data,
                                             GDestroyNotify upload_destroy,
                                             GskUrlTransferFunc handler,
                                             gpointer data,
                                             GDestroyNotify destroy,
                                             GError **error);
GskUrlTransfer* gsk_url_transfer_new        (GskUrl *url);
void        gsk_url_transfer_set_handler    (GskUrlTransfer *transfer,
                                             GskUrlTransferFunc handler,
                                             gpointer data,
                                             GDestroyNotify destroy);
void        gsk_url_transfer_set_url        (GskUrlTransfer *transfer,
                                             GskUrl *url);
void        gsk_url_transfer_set_upload     (GskUrlTransfer *transfer,
                                             GskUrlUploadFunc func,
                                             gpointer data,
                                             GDestroyNotify destroy);
void        gsk_url_transfer_set_upload_packet
                                            (GskUrlTransfer *transfer,
                                             GskPacket *packet);
void        gsk_url_transfer_set_oneshot_upload
                                            (GskUrlTransfer *transfer,
                                             GskStream *stream,
                                             gssize size);
void        gsk_url_transfer_set_timeout    (GskUrlTransfer *transfer,
                                             guint millis);
void        gsk_url_transfer_clear_timeout  (GskUrlTransfer *transfer);
void        gsk_url_transfer_set_follow_redirects
                                            (GskUrlTransfer *transfer,
                                             gboolean follow_redirs);
void        gsk_url_transfer_set_address_hint
                                            (GskUrlTransfer *transfer,
                                             GskSocketAddress *address);
gboolean    gsk_url_transfer_start          (GskUrlTransfer *transfer,
                                             GError **error);
void        gsk_url_transfer_cancel         (GskUrlTransfer *transfer);
gboolean    gsk_url_transfer_has_upload     (GskUrlTransfer *transfer);
GskStream*  gsk_url_transfer_create_upload  (GskUrlTransfer *transfer,
                                             gssize *size_out,
                                             GError **error);
gboolean    gsk_url_transfer_peek_expects_download_stream
                                            (GskUrlTransfer *transfer);
gboolean    gsk_url_transfer_is_done        (GskUrlTransfer *transfer);
void        gsk_url_transfer_set_address    (GskUrlTransfer *transfer,
                                             GskSocketAddress *addr);
gboolean    gsk_url_transfer_add_redirect   (GskUrlTransfer *transfer,
                                             GObject *request,
                                             GObject *response,
                                             gboolean is_permanent,
                                             GskUrl *dest_url);
void        gsk_url_transfer_set_download   (GskUrlTransfer *transfer,
                                             GskStream *content);
void        gsk_url_transfer_set_request    (GskUrlTransfer *transfer,
                                             GObject *request);
void        gsk_url_transfer_set_response   (GskUrlTransfer *transfer,
                                             GObject *response);
void        gsk_url_transfer_set_error      (GskUrlTransfer *transfer,
                                             const GError *error);
void        gsk_url_transfer_take_error     (GskUrlTransfer *transfer,
                                             GError *error);
void        gsk_url_transfer_notify_done    (GskUrlTransfer *transfer,
                                             GskUrlTransferResult result);
void        gsk_url_transfer_class_register (GskUrlScheme scheme,
                                             GskUrlTransferClass *transfer_class);
char*       gsk_url_transfer_get_state_string
                                            (GskUrlTransfer *transfer);
GskStream*  gsk_url_transfer_stream_new     (GskUrlTransfer *transfer,
                                             GError **error);

Object Hierarchy


  GObject
   +----GskUrlTransfer
         +----GskUrlTransferHttp
         +----GskUrlTransferFile

Description

A GskUrlTransfer represents a single upload and/or download with a resource designed by a URL. Although most of the interface is URL-scheme independent, for convenience we allow users to see the URL-specific portions as well.

Some types of URLs are download only, and others support upload, but possibly not at the same time.

The basic plan is to make a GskUrlTransfer object. If you wish to upload, provide a way of constructing an upload content-stream. If you wish to download, provide a function that will be called with the downloading content-stream. Additional configuration may be done: for example, whether to follow redirections.

The transfer which is returned from gsk_url_transfer_new() is in an "unstarted" state. After you are done configuring it, you should invoke gsk_url_transfer_start() to begin doing actual work.

You should at least connect a handler to it before you start it using gsk_url_transfer_set_handler().

Your handler is guaranteed to be called exactly once, after or during the invocation of gsk_url_transfer_start().

Internally, the URL-transfer code maintains a mapping from url-scheme to a list of GskUrlTransferClasses responsible for that type of URL. When gsk_url_transfer_new(url) is called, each handler for the url's scheme is tried in sequence until one is found that accepts the URL, or NULL will returned if no suitable class is found.

Details

GskUrlTransferRedirect

typedef struct {
  gboolean is_permanent;
  GskUrl *url;
  GObject *request;
  GObject *response;
  GskUrlTransferRedirect *next;
} GskUrlTransferRedirect;

A node in the linked-list of redirections we have receieved.

gboolean is_permanent; whether the redirect is permanent (versus temporary).
GskUrl *url; the location that we have been redirected to.
GObject *request; the request object.
GObject *response; the response object.
GskUrlTransferRedirect *next; next redirect chronologically.

enum GskUrlTransferResult

typedef enum
{
  GSK_URL_TRANSFER_ERROR_BAD_REQUEST,
  GSK_URL_TRANSFER_ERROR_BAD_NAME,
  GSK_URL_TRANSFER_ERROR_NO_SERVER,
  GSK_URL_TRANSFER_ERROR_NOT_FOUND,
  GSK_URL_TRANSFER_ERROR_SERVER_ERROR,
  GSK_URL_TRANSFER_ERROR_UNSUPPORTED,
  GSK_URL_TRANSFER_ERROR_TIMED_OUT,
  GSK_URL_TRANSFER_ERROR_REDIRECT_LOOP,
  GSK_URL_TRANSFER_REDIRECT,
  GSK_URL_TRANSFER_CANCELLED,
  GSK_URL_TRANSFER_SUCCESS
} GskUrlTransferResult;

The result element of transfer is prepared before the user's done-handler is invoked and is a general indicator of the result of the transfer.

This enumeration therefore lists all possible ways that a Url-transfer can conclude.

For error values, the "error" member of transfer should be set.

GSK_URL_TRANSFER_ERROR_BAD_REQUEST Some aspect request was invalidly formed: for example, the user provided a bad SSL certificate or upload-function.
GSK_URL_TRANSFER_ERROR_BAD_NAME DNS failed on the hostname.
GSK_URL_TRANSFER_ERROR_NO_SERVER Problem connecting to the server.
GSK_URL_TRANSFER_ERROR_NOT_FOUND Server indicated the entity was not found.
GSK_URL_TRANSFER_ERROR_SERVER_ERROR Server indicated another error.
GSK_URL_TRANSFER_ERROR_UNSUPPORTED Request was not supported (either by the server, the protocol, or the url-transfer-code).
GSK_URL_TRANSFER_ERROR_TIMED_OUT Request timed out.
GSK_URL_TRANSFER_ERROR_REDIRECT_LOOP Request redirection looped circulurly.
GSK_URL_TRANSFER_REDIRECT The URL transfer code was not instructed to follow redirects, but a redirect was encountered. See the transfer's redirect_url member.
GSK_URL_TRANSFER_CANCELLED The transfer was aborted because gsk_url_transfer_cancel() was called on it.
GSK_URL_TRANSFER_SUCCESS The transfer initiated successfully (the data may not be transferred yet, though)

GSK_URL_TRANSFER_N_RESULTS

#define GSK_URL_TRANSFER_N_RESULTS      (GSK_URL_TRANSFER_SUCCESS+1)

Number of result-codes, seldom needed.


gsk_url_transfer_result_name ()

const char* gsk_url_transfer_result_name    (GskUrlTransferResult result);

result: the enumeration value.

Convert a GskUrlTransferResult value into a human-readable string.

Get a mixed-case human-readable name for the Transfer-Result.

result : the result code.
Returns : the constant string.

GskUrlTransferFunc ()

void        (*GskUrlTransferFunc)           (GskUrlTransfer *info,
                                             gpointer user_data);

A function that is called when the transfer is "done". This function is called if the transfer is successful, or has an error, or times out, or is cancelled.

It will only be called after gsk_url_transfer_start() returns TRUE.

info : the object that contains information about the transfer.
user_data : data registered with gsk_url_transfer() or gsk_url_transfer_set_handler().

GskUrlUploadFunc ()

GskStream*  (*GskUrlUploadFunc)             (gpointer upload_data,
                                             gssize *size_out,
                                             GError **error);

In order to upload content and still follow redirects, we need to be able to make any number of upload streams. Therefore, in order to upload data, you may wish to provide a function like this.

If you don't care about POST-redirects, as you probably don't, you can just use gsk_url_transfer_set_oneshot_upload().

upload_data : data passed into gsk_url_transfer() or gsk_url_transfer_set_upload().
size_out : optionally set the length of the stream in bytes. Setting it to -1 is equivalent to not setting it, and indicates that the length is not known in advance.
error : if you cannot make a stream, the error should be set.
Returns : a newly allocated stream, or NULL if an error occurs.

GskUrlTransfer

typedef struct {
  /* --- information prepared for the handler --- */
  GskUrlTransferResult result;
  GskUrl *url;
  GSList *redirect_urls;
  GskUrlTransferRedirect *first_redirect, *last_redirect;
  GskSocketAddress *address;

  /* may be available: protocol-specific headers */
  GObject *request;     /* a GskHttpRequest probably */
  GObject *response;    /* a GskHttpResponse probably */

  GskStream *content;   /* the downloading content */

  /* the last redirect (if any) */
  GskUrl *redirect_url; /* [just a peeked version of last_redirect->url, not a ref] */
  gboolean redirect_is_permanent;

  /* ERROR status codes */
  GError *error;
} GskUrlTransfer;

A GObject that represents a transfer of data with the entity responsible for that type of URL.

GskUrlTransferResult result; code indicating final status of the transfer. (only valid in the "done" state)
GskUrl *url; the url of the initial request.
GSList *redirect_urls; XXX: UNUSED
GskUrlTransferRedirect *first_redirect; first redirect in list
GskUrlTransferRedirect *last_redirect; last redirect in list
GskSocketAddress *address; socket-address of the server for this url.
GObject *request; request header.
GObject *response; response header.
GskStream *content; downloading data.
GskUrl *redirect_url; target of first redirect.
gboolean redirect_is_permanent; whether the redirection was permenant (versus temporary)
GError *error; the error, if something went wrong.

gsk_url_transfer ()

gboolean    gsk_url_transfer                (GskUrl *url,
                                             GskUrlUploadFunc upload_func,
                                             gpointer upload_data,
                                             GDestroyNotify upload_destroy,
                                             GskUrlTransferFunc handler,
                                             gpointer data,
                                             GDestroyNotify destroy,
                                             GError **error);

Begin a upload and/or download with a URL. There is no way to cancel this transfer.

If you wish to perform an upload, provide a function that can create the stream of content to upload on demand. Note that the upload_destroy() method is called only once the transfer is done and all the upload streams are finalized. Therefore, you can assume that the upload_data will be available for all your upload-streams.

The handler/data/destroy triple is used for result notification. handler() is always invoked exactly once. To find out how things went, the handler() should almost always start by examining transfer->result.

url : the URL to which to upload or from which to download data.
upload_func : optional function that can create the upload's content as a GskStream.
upload_data : data which can be used by the upload function.
upload_destroy : optional function that will be notified when upload() will no longer be called (note that the streams it created may still be extant though).
handler : function to be called with the transfer request is done. (The transfer content itself is just provided as a stream though-- only after reading the stream is the transfer truly done) This function may also be called in a number of error cases.
data : data to pass to the handler function.
destroy : function to call when you are done with data.
error : place to put the error if anything goes wrong.
Returns : whether the transfer began. Unsupported URL schemes and malformed URLs are the most common ways for this function to fail.

gsk_url_transfer_new ()

GskUrlTransfer* gsk_url_transfer_new        (GskUrl *url);

Create a URL transfer of the appropriate type for the given URL. We try the registered classes, in order.

url : the URL to create a transfer object for.
Returns : a newly allocated Transfer object, or NULL if no transfer-class could handle the URL.

gsk_url_transfer_set_handler ()

void        gsk_url_transfer_set_handler    (GskUrlTransfer *transfer,
                                             GskUrlTransferFunc handler,
                                             gpointer data,
                                             GDestroyNotify destroy);

The handler/data/destroy triple is used for result notification. handler() is always invoked exactly once. To find out how things went, the handler() should almost always start by examining transfer->result.

transfer : the Transfer to affect.
handler : function to be called with the transfer request is done. (The transfer content itself is just provided as a stream though-- only after reading the stream is the transfer truly done) This function may also be called in a number of error cases.
data : data to pass to the handler function.
destroy : function to call when you are done with data.

gsk_url_transfer_set_url ()

void        gsk_url_transfer_set_url        (GskUrlTransfer *transfer,
                                             GskUrl *url);

Set the URL that is the target of this transfer. This can only be done once, before the transfer is started.

You seldom need to use this function, as it is called by gsk_url_transfer_new().

transfer : the Transfer to affect.
url : the URL to which to upload or from which to download data.

gsk_url_transfer_set_upload ()

void        gsk_url_transfer_set_upload     (GskUrlTransfer *transfer,
                                             GskUrlUploadFunc func,
                                             gpointer data,
                                             GDestroyNotify destroy);

Set the upload stream as generally as possible. Actually you must provide a function that can make an upload stream on demand-- this is necessary to get redirects right.

The destroy() function will be called after no more upload-streams need to be created-- it is quite possible that not all upload-streams have been finalized by the time the destroy() is invoked.

If you don't care about redirects, you can use gsk_url_transfer_set_oneshot_upload().

If you have a slab of memory that you want to use as the upload stream, consider using gsk_url_transfer_set_upload_packet().

transfer : the Transfer to affect.
func : function that can create the upload's content as a GskStream.
data : data which can be used by the upload function.
destroy : optional function that will be notified when upload() will no longer be called (note that the streams it created may still be extant though).

gsk_url_transfer_set_upload_packet ()

void        gsk_url_transfer_set_upload_packet
                                            (GskUrlTransfer *transfer,
                                             GskPacket *packet);

Set the upload stream in an easy, reliable way using a GskPacket.

transfer : the Transfer to affect.
packet : the GskPacket containing the upload content as data.

gsk_url_transfer_set_oneshot_upload ()

void        gsk_url_transfer_set_oneshot_upload
                                            (GskUrlTransfer *transfer,
                                             GskStream *stream,
                                             gssize size);

Set the content to upload to the remote URL, as a GskStream.

Since streams can only be read once, this method only works on URLs that do not require redirection.

transfer : the Transfer to affect.
stream : the upload content stream.
size : the length of the stream in bytes, or -1 if you don't know.

gsk_url_transfer_set_timeout ()

void        gsk_url_transfer_set_timeout    (GskUrlTransfer *transfer,
                                             guint millis);

Set the timeout on the download.

This can be used to avoid hanging on slow servers.

This must be called before the transfer is started (with gsk_url_transfer_start).

transfer : the Transfer to affect.
millis : milliseconds to wait before aborting the transfer.

gsk_url_transfer_clear_timeout ()

void        gsk_url_transfer_clear_timeout  (GskUrlTransfer *transfer);

Clear the timeout on the download.

This must be called before the transfer is started (with gsk_url_transfer_start).

transfer : the Transfer to affect.

gsk_url_transfer_set_follow_redirects ()

void        gsk_url_transfer_set_follow_redirects
                                            (GskUrlTransfer *transfer,
                                             gboolean follow_redirs);

Configure how the transfer will behave when it encounters redirection responses.

The default behavior is to follow redirects, adding them to the list of redirects, but not notifying the user until we reach a real page (or error).

If follow_redirects is FALSE, then we are done even if the download led to a redirect.

transfer : the Transfer to affect.
follow_redirs : whether to follow redirect responses.

gsk_url_transfer_set_address_hint ()

void        gsk_url_transfer_set_address_hint
                                            (GskUrlTransfer *transfer,
                                             GskSocketAddress *address);

To avoid DNS lookups in very bulky transfer situations, DNS may be bypassed and replaced with this address.

Chances are, you want to suppress redirects to: otherwise, DNS may be used on the redirected URLs.

transfer : the Transfer to affect.
address : the socket-address to use for connecting, possibly with the wrong port (the port will be overridden by the URL's port).

gsk_url_transfer_start ()

gboolean    gsk_url_transfer_start          (GskUrlTransfer *transfer,
                                             GError **error);

Begin the upload and/or download. (Maybe start with name-lookup).

transfer : the Transfer to affect.
error : place to put the error if anything goes wrong.
Returns : whether the transfer started successfully. If it returns TRUE, you are guaranteed to receive your done-notification. If is returns FALSE, you will definitely not receive done-notification.

gsk_url_transfer_cancel ()

void        gsk_url_transfer_cancel         (GskUrlTransfer *transfer);

Abort a running transfer.

If you registered a handler, it will be called with result GSK_URL_TRANSFER_CANCELLED.

transfer : the Transfer to affect.

gsk_url_transfer_has_upload ()

gboolean    gsk_url_transfer_has_upload     (GskUrlTransfer *transfer);

Figure out whether this transfer has upload data.

This function should only be needed by implementors of types of GskUrlTransfer.

transfer : the Transfer to query.
Returns : whether the transfer has upload data.

gsk_url_transfer_create_upload ()

GskStream*  gsk_url_transfer_create_upload  (GskUrlTransfer *transfer,
                                             gssize *size_out,
                                             GError **error);

Create a upload stream for this transfer based on the user's creator function.

This function should only be needed by implementors of types of GskUrlTransfer.

transfer : the Transfer to use.
size_out : the size of the stream in bytes, or -1 if the size is unknown.
error : optional location to store the GError if there is a problem.
Returns : a newly allocated GskStream, or NULL if an error occurs.

gsk_url_transfer_peek_expects_download_stream ()

gboolean    gsk_url_transfer_peek_expects_download_stream
                                            (GskUrlTransfer *transfer);

This function can be used to see if download-content is expected.

This function should only be needed by implementors of types of GskUrlTransfer.

transfer : the Transfer to use. returns: whether this transfer has a download handler.
Returns :

gsk_url_transfer_is_done ()

gboolean    gsk_url_transfer_is_done        (GskUrlTransfer *transfer);

Find out whether the transfer is done. The transfer is done iff the callback has been invoked.

transfer : the Transfer to query.
Returns : whether the function is done.

gsk_url_transfer_set_address ()

void        gsk_url_transfer_set_address    (GskUrlTransfer *transfer,
                                             GskSocketAddress *addr);

Set the socket-address for informational purposes. This is occasionally interesting to the user of the Transfer.

This function should only be needed by implementors of types of GskUrlTransfer.

transfer : the Transfer to affect.
addr : the address of the host whose lookup was completed.

gsk_url_transfer_add_redirect ()

gboolean    gsk_url_transfer_add_redirect   (GskUrlTransfer *transfer,
                                             GObject *request,
                                             GObject *response,
                                             gboolean is_permanent,
                                             GskUrl *dest_url);

Add an entry to the list of redirects that we have encountered while trying to service this request.

Most users of GskUrlTransfer won't care about these redirects-- they are provided to the rare client that cares about the redirect-path. More commonly, users merely wish to suppress redirect handling: that can be done more easily by gsk_url_transfer_set_follow_redirects().

This function should only be needed by implementors of types of GskUrlTransfer.

transfer : the Transfer to affect.
request : request object for this segment of the transfer.
response : response object for this segment of the transfer.
is_permanent : whether the content is permanently relocated to this address.
dest_url : the URL to which we have been redirected.
Returns : whether the redirect was allowed (it is disallowed if it is a circular redirect. In that case, we will set 'transfer->error', and call gsk_url_transfer_notify_done().

gsk_url_transfer_set_download ()

void        gsk_url_transfer_set_download   (GskUrlTransfer *transfer,
                                             GskStream *content);

Set the incoming-content that is associated with this transfer. This will used by the user of the Transfer.

This function should only be needed by implementors of types of GskUrlTransfer.

transfer : the Transfer to affect.
content : the content-stream for the downloaded data.

gsk_url_transfer_set_request ()

void        gsk_url_transfer_set_request    (GskUrlTransfer *transfer,
                                             GObject *request);

Set the outgoing-request header data for this transaction.

This function should only be needed by implementors of types of GskUrlTransfer.

transfer : the Transfer to affect.
request : the request object to store in the transfer information.

gsk_url_transfer_set_response ()

void        gsk_url_transfer_set_response   (GskUrlTransfer *transfer,
                                             GObject *response);

Set the incoming-response header data for this transaction.

This function should only be needed by implementors of types of GskUrlTransfer.

transfer : the Transfer to affect.
response : the response object to store in the transfer information.

gsk_url_transfer_set_error ()

void        gsk_url_transfer_set_error      (GskUrlTransfer *transfer,
                                             const GError *error);

Set the error field for this transaction. A copy of the error parameter is made.

This function should only be needed by implementors of types of GskUrlTransfer.

transfer : the Transfer to affect.
error : the error to associate with the transfer.

gsk_url_transfer_take_error ()

void        gsk_url_transfer_take_error     (GskUrlTransfer *transfer,
                                             GError *error);

Set the error field for this transaction. The error parameter will be freed eventually by the GskUrlTransfer.

This function should only be needed by implementors of types of GskUrlTransfer.

transfer : the Transfer to affect.
error : the error to associate with the transfer.

gsk_url_transfer_notify_done ()

void        gsk_url_transfer_notify_done    (GskUrlTransfer *transfer,
                                             GskUrlTransferResult result);

Transition the transfer to the DONE state, and invoke the user's callback (if any). This function may only be invoked once per transfer.

This function should only be needed by implementors of types of GskUrlTransfer.

transfer : the Transfer to affect.
result : the transfer's result status code.

gsk_url_transfer_class_register ()

void        gsk_url_transfer_class_register (GskUrlScheme scheme,
                                             GskUrlTransferClass *transfer_class);

Register a class of URL transfer that can handle a given scheme. It will only be instantiated if the class' test method

scheme : the URL scheme that this class of transfer can handle.
transfer_class : the class that can handle the URL type.

gsk_url_transfer_get_state_string ()

char*       gsk_url_transfer_get_state_string
                                            (GskUrlTransfer *transfer);

Get a newly allocated, human-readable description of the state of the transfer.

transfer : the transfer to describe.
Returns : the newly-allocated string.

gsk_url_transfer_stream_new ()

GskStream*  gsk_url_transfer_stream_new     (GskUrlTransfer *transfer,
                                             GError **error);

This code will start the transfer, and return a stream that you can trap immediately.

transfer : the transfer. must not be started.
error : optional location to store the GError if there is a problem.
Returns : the new stream, or NULL if an error occurred.

See Also

GskUrlTransferHttp.