[libsoup/carlosgc/simple-api: 2/4] session: Add new simple API to retrieve a URI
- From: Carlos Garcia Campos <carlosgc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsoup/carlosgc/simple-api: 2/4] session: Add new simple API to retrieve a URI
- Date: Mon, 19 Oct 2020 12:11:38 +0000 (UTC)
commit 084a75055ed8b503465591648dbdb167276830b8
Author: Carlos Garcia Campos <cgarcia igalia com>
Date: Mon Oct 19 11:28:15 2020 +0200
session: Add new simple API to retrieve a URI
It adds soup_session_get() and soup_session_get_bytes() and the async
alternatives to easily retrieve the contents of a URI. It supports the
same URIs as SoupRequest API that will be removed.
docs/reference/libsoup-3.0-sections.txt | 10 +
libsoup/soup-session.c | 943 ++++++++++++++++++++++++++++++++
libsoup/soup-session.h | 50 ++
tests/session-test.c | 358 +++++++++++-
4 files changed, 1345 insertions(+), 16 deletions(-)
---
diff --git a/docs/reference/libsoup-3.0-sections.txt b/docs/reference/libsoup-3.0-sections.txt
index 64989b04..aa89d8c0 100644
--- a/docs/reference/libsoup-3.0-sections.txt
+++ b/docs/reference/libsoup-3.0-sections.txt
@@ -397,6 +397,7 @@ SoupAuthDomainDigestClass
<FILE>soup-session</FILE>
<TITLE>SoupSession</TITLE>
SoupSession
+SoupSessionError
<SUBSECTION>
soup_session_new
soup_session_new_with_options
@@ -414,6 +415,13 @@ soup_session_send
soup_session_send_async
soup_session_send_finish
<SUBSECTION>
+soup_session_get
+soup_session_get_async
+soup_session_get_finish
+soup_session_get_bytes
+soup_session_get_bytes_async
+soup_session_get_bytes_finish
+<SUBSECTION>
soup_session_websocket_connect_async
soup_session_websocket_connect_finish
<SUBSECTION>
@@ -459,9 +467,11 @@ SOUP_SESSION
SOUP_SESSION_CLASS
SOUP_SESSION_GET_CLASS
SOUP_TYPE_SESSION
+SOUP_SESSION_ERROR
SoupSessionClass
soup_session_get_type
soup_request_error_quark
+soup_session_error_quark
<SUBSECTION Private>
SoupSocket
SoupConnection
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index f9fb7176..d3c82811 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -17,6 +17,7 @@
#include "auth/soup-auth-ntlm.h"
#include "cache/soup-cache-private.h"
#include "soup-connection.h"
+#include "soup-directory-input-stream.h"
#include "soup-message-private.h"
#include "soup-misc.h"
#include "soup-message-queue.h"
@@ -208,6 +209,34 @@ enum {
LAST_PROP
};
+/**
+ * SOUP_SESSION_ERROR:
+ *
+ * A #GError domain for #SoupSession<!-- -->-related errors. Used with
+ * #SoupSessionError.
+ */
+/**
+ * SoupSessionError:
+ * @SOUP_SESSION_ERROR_BAD_URI: the URI could not be parsed
+ * @SOUP_SESSION_ERROR_UNSUPPORTED_URI_SCHEME: the URI scheme is not
+ * supported by this #SoupSession
+ * @SOUP_SESSION_ERROR_PARSING: the server's response could not
+ * be parsed
+ * @SOUP_SESSION_ERROR_ENCODING: the server's response was in an
+ * unsupported format
+ *
+ * A #SoupSession error.
+ */
+
+GQuark
+soup_session_error_quark (void)
+{
+ static GQuark error;
+ if (!error)
+ error = g_quark_from_static_string ("soup_session_error_quark");
+ return error;
+}
+
static void
soup_session_init (SoupSession *session)
{
@@ -3747,6 +3776,920 @@ soup_session_send (SoupSession *session,
return stream;
}
+typedef struct {
+ goffset content_length;
+ char *content_type;
+} SessionGetAsyncData;
+
+static void
+session_get_async_data_free (SessionGetAsyncData *data)
+{
+ g_free (data->content_type);
+ g_slice_free (SessionGetAsyncData, data);
+}
+
+static void
+session_get_async_data_set_content_type (SessionGetAsyncData *data,
+ const char *content_type,
+ GHashTable *params)
+{
+ GString *type;
+
+ type = g_string_new (content_type);
+ if (params) {
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init (&iter, params);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ g_string_append (type, "; ");
+ soup_header_g_string_append_param (type, key, value);
+ }
+ }
+
+ g_free (data->content_type);
+ data->content_type = g_string_free (type, FALSE);
+}
+
+static void
+http_input_stream_ready_cb (SoupSession *session,
+ GAsyncResult *result,
+ GTask *task)
+{
+ GInputStream *stream;
+ GError *error = NULL;
+
+ stream = soup_session_send_finish (session, result, &error);
+ if (stream)
+ g_task_return_pointer (task, stream, g_object_unref);
+ else
+ g_task_return_error (task, error);
+ g_object_unref (task);
+}
+
+static void
+get_http_content_sniffed (SoupMessage *msg,
+ const char *content_type,
+ GHashTable *params,
+ SessionGetAsyncData *data)
+{
+ session_get_async_data_set_content_type (data, content_type, params);
+}
+
+static void
+get_http_got_headers (SoupMessage *msg,
+ SessionGetAsyncData *data)
+{
+ goffset content_length;
+ const char *content_type;
+ GHashTable *params = NULL;
+
+ content_length = soup_message_headers_get_content_length (msg->response_headers);
+ data->content_length = content_length != 0 ? content_length : -1;
+ content_type = soup_message_headers_get_content_type (msg->response_headers, ¶ms);
+ session_get_async_data_set_content_type (data, content_type, params);
+ g_clear_pointer (¶ms, g_hash_table_destroy);
+}
+
+static void
+soup_session_get_http_async (SoupSession *session,
+ SoupURI *uri,
+ GTask *task)
+{
+ SoupMessage *msg;
+ SessionGetAsyncData *data;
+
+ if (!SOUP_URI_VALID_FOR_HTTP (uri)) {
+ char *uri_string = soup_uri_to_string (uri, FALSE);
+
+ g_task_return_new_error (task,
+ SOUP_SESSION_ERROR,
+ SOUP_SESSION_ERROR_BAD_URI,
+ _("Invalid “%s” URI: %s"),
+ uri->scheme,
+ uri_string);
+ g_free (uri_string);
+ g_object_unref (task);
+ return;
+ }
+
+ data = g_task_get_task_data (task);
+
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
+ g_signal_connect (msg, "content-sniffed",
+ G_CALLBACK (get_http_content_sniffed), data);
+ g_signal_connect (msg, "got-headers",
+ G_CALLBACK (get_http_got_headers), data);
+ soup_session_send_async (session, msg,
+ g_task_get_priority (task),
+ g_task_get_cancellable (task),
+ (GAsyncReadyCallback)http_input_stream_ready_cb,
+ task);
+ g_object_unref (msg);
+}
+
+static void
+file_enumerate_ready_cb (GFile *file,
+ GAsyncResult *result,
+ GTask *task)
+{
+ GFileEnumerator *enumerator;
+ GError *error = NULL;
+
+ enumerator = g_file_enumerate_children_finish (file, result, &error);
+ if (enumerator) {
+ GInputStream *stream;
+ SoupURI *uri;
+ char *uri_string;
+ SessionGetAsyncData *data;
+
+ uri_string = g_file_get_uri (file);
+ uri = soup_uri_new (uri_string);
+ g_free (uri_string);
+ stream = soup_directory_input_stream_new (enumerator, uri);
+ soup_uri_free (uri);
+ g_object_unref (enumerator);
+
+ data = g_task_get_task_data (task);
+ data->content_length = -1;
+ data->content_type = g_strdup ("text/html");
+
+ g_task_return_pointer (task, stream, g_object_unref);
+ } else {
+ g_task_return_error (task, error);
+ }
+ g_object_unref (task);
+}
+
+static void
+file_read_ready_cb (GFile *file,
+ GAsyncResult *result,
+ GTask *task)
+{
+ GInputStream *stream;
+ GError *error = NULL;
+
+ stream = G_INPUT_STREAM (g_file_read_finish (file, result, &error));
+ if (stream)
+ g_task_return_pointer (task, stream, g_object_unref);
+ else
+ g_task_return_error (task, error);
+ g_object_unref (task);
+}
+
+static void
+file_query_info_ready_cb (GFile *file,
+ GAsyncResult *result,
+ GTask *task)
+{
+ GFileInfo *info;
+
+ info = g_file_query_info_finish (file, result, NULL);
+ if (info) {
+ SessionGetAsyncData *data;
+ const char *content_type;
+
+ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
+ g_file_enumerate_children_async (file,
+ "*",
+ G_FILE_QUERY_INFO_NONE,
+ g_task_get_priority (task),
+ g_task_get_cancellable (task),
+ (GAsyncReadyCallback)file_enumerate_ready_cb,
+ task);
+ g_object_unref (info);
+ return;
+ }
+
+ data = g_task_get_task_data (task);
+ data->content_length = g_file_info_get_size (info);
+
+ content_type = g_file_info_get_content_type (info);
+ if (content_type)
+ data->content_type = g_content_type_get_mime_type (content_type);
+ if (!data->content_type)
+ data->content_type = g_strdup ("application/octet-stream");
+
+ g_object_unref (info);
+ }
+
+ g_file_read_async (file,
+ g_task_get_priority (task),
+ g_task_get_cancellable (task),
+ (GAsyncReadyCallback)file_read_ready_cb,
+ task);
+}
+
+#ifdef G_OS_WIN32
+static void
+windowsify_file_uri_path (char *path)
+{
+ char *p, *slash;
+
+ /* Copied from g_filename_from_uri(), which we can't use
+ * directly because it rejects invalid URIs that we need to
+ * keep.
+ */
+
+ /* Turn slashes into backslashes, because that's the canonical spelling */
+ p = path;
+ while ((slash = strchr (p, '/')) != NULL) {
+ *slash = '\\';
+ p = slash + 1;
+ }
+
+ /* Windows URIs with a drive letter can be like
+ * "file://host/c:/foo" or "file://host/c|/foo" (some Netscape
+ * versions). In those cases, start the filename from the
+ * drive letter.
+ */
+ if (g_ascii_isalpha (path[1])) {
+ if (path[2] == '|')
+ path[2] = ':';
+ if (path[2] == ':')
+ memmove (path, path + 1, strlen (path));
+ }
+}
+#endif /* G_OS_WIN32 */
+
+static void
+soup_session_get_file_async (SoupSession *session,
+ SoupURI *uri,
+ GTask *task)
+{
+ GFile *file;
+ char *path;
+
+ /* "file:/foo" is not valid, but it must be "file:///..." or "file://localhost/..." */
+ if (!uri->host || (*uri->host && g_ascii_strcasecmp (uri->host, "localhost") != 0)) {
+ char *uri_string = soup_uri_to_string (uri, FALSE);
+
+ g_task_return_new_error (task,
+ SOUP_SESSION_ERROR,
+ SOUP_SESSION_ERROR_BAD_URI,
+ _("Invalid “%s” URI: %s"),
+ uri->scheme,
+ uri_string);
+ g_free (uri_string);
+ g_object_unref (task);
+ return;
+ }
+
+ path = soup_uri_decode (uri->path);
+#ifdef G_OS_WIN32
+ windowsify_file_uri_path (decoded_path);
+#endif
+
+ if (uri->scheme == SOUP_URI_SCHEME_RESOURCE) {
+ char *uri_string;
+
+ uri_string = g_strdup_printf ("resource://%s", path);
+ file = g_file_new_for_uri (uri_string);
+ g_free (uri_string);
+ } else
+ file = g_file_new_for_path (path);
+ g_free (path);
+
+ g_file_query_info_async (file,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE ","
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
+ G_FILE_ATTRIBUTE_STANDARD_SIZE,
+ G_FILE_QUERY_INFO_NONE,
+ g_task_get_priority (task),
+ g_task_get_cancellable (task),
+ (GAsyncReadyCallback)file_query_info_ready_cb,
+ task);
+}
+
+#define BASE64_INDICATOR ";base64"
+#define BASE64_INDICATOR_LEN (sizeof (";base64") - 1)
+
+static GBytes *
+soup_session_decode_data_uri (SoupSession *session,
+ SoupURI *uri,
+ char **content_type)
+{
+ char *uri_string;
+ const char *comma, *start, *end;
+ gboolean base64 = FALSE;
+ GBytes *bytes = NULL;
+
+ if (content_type)
+ *content_type = NULL;
+
+ uri_string = soup_uri_to_string (uri, FALSE);
+ start = uri_string + 5;
+ comma = strchr (start, ',');
+ if (comma && comma != start) {
+ /* Deal with MIME type / params */
+ if (comma >= start + BASE64_INDICATOR_LEN && !g_ascii_strncasecmp (comma -
BASE64_INDICATOR_LEN, BASE64_INDICATOR, BASE64_INDICATOR_LEN)) {
+ end = comma - BASE64_INDICATOR_LEN;
+ base64 = TRUE;
+ } else
+ end = comma;
+
+ if (content_type && end != start)
+ *content_type = soup_uri_decoded_copy (start, end - start, NULL);
+ }
+
+ if (content_type && !*content_type)
+ *content_type = g_strdup ("text/plain;charset=US-ASCII");
+
+ if (comma)
+ start = comma + 1;
+
+ if (*start) {
+ gsize content_length;
+ int decoded_length = 0;
+ guchar *buffer = (guchar *)soup_uri_decoded_copy (start, strlen (start),
+ &decoded_length);
+
+ if (base64)
+ buffer = g_base64_decode_inplace ((gchar*)buffer, &content_length);
+ else
+ content_length = decoded_length;
+
+ bytes = g_bytes_new_take (buffer, content_length);
+ } else
+ bytes = g_bytes_new_static (NULL, 0);
+ g_free (uri_string);
+
+ return bytes;
+}
+
+static void
+soup_session_get_data_async (SoupSession *session,
+ SoupURI *uri,
+ GTask *task)
+{
+ SessionGetAsyncData *data;
+ GBytes *body;
+
+ if (uri->host != NULL) {
+ char *uri_string = soup_uri_to_string (uri, FALSE);
+
+ g_task_return_new_error (task,
+ SOUP_SESSION_ERROR,
+ SOUP_SESSION_ERROR_BAD_URI,
+ _("Invalid “%s” URI: %s"),
+ uri->scheme,
+ uri_string);
+ g_free (uri_string);
+ g_object_unref (task);
+ return;
+ }
+
+ data = g_task_get_task_data (task);
+ body = soup_session_decode_data_uri (session, uri, &data->content_type);
+ data->content_length = g_bytes_get_size (body);
+
+ g_task_return_pointer (task,
+ g_memory_input_stream_new_from_bytes (body),
+ g_object_unref);
+ g_bytes_unref (body);
+ g_object_unref (task);
+}
+
+/**
+ * soup_session_get_async:
+ * @session: a #SoupSession
+ * @uri: a URI, in string form
+ * @io_priority: the I/O priority of the request
+ * @cancellable: a #GCancellable
+ * @callback: the callback to invoke
+ * @user_data: data for @callback
+ *
+ * Asynchronously retrieve @uri.
+ *
+ * This function supports several URI schemes (http, https, file, resource and data). If
+ * an unsupported URI is passed it will fail with %SOUP_SESSION_ERROR_UNSUPPORTED_URI_SCHEME
+ * error.
+ *
+ * When the operation is finished, @callback will be called. You can then
+ * call soup_session_get_finish() to get the result of the operation.
+ */
+void
+soup_session_get_async (SoupSession *session,
+ const char *uri,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ SoupURI *soup_uri;
+
+ g_return_if_fail (SOUP_IS_SESSION (session));
+ g_return_if_fail (uri != NULL);
+
+ task = g_task_new (session, cancellable, callback, user_data);
+ g_task_set_priority (task, io_priority);
+
+ soup_uri = soup_uri_new (uri);
+ if (!soup_uri) {
+ g_task_return_new_error (task,
+ SOUP_SESSION_ERROR,
+ SOUP_SESSION_ERROR_BAD_URI,
+ _("Could not parse URI “%s”"),
+ uri);
+ g_object_unref (task);
+ return;
+ }
+
+ g_task_set_task_data (task,
+ g_slice_new0 (SessionGetAsyncData),
+ (GDestroyNotify)session_get_async_data_free);
+
+ if (soup_uri->scheme == SOUP_URI_SCHEME_HTTP || soup_uri->scheme == SOUP_URI_SCHEME_HTTPS)
+ soup_session_get_http_async (session, soup_uri, task);
+ else if (soup_uri->scheme == SOUP_URI_SCHEME_FILE || soup_uri->scheme == SOUP_URI_SCHEME_RESOURCE)
+ soup_session_get_file_async (session, soup_uri, task);
+ else if (soup_uri->scheme == SOUP_URI_SCHEME_DATA)
+ soup_session_get_data_async (session, soup_uri, task);
+ else {
+ g_task_return_new_error (task,
+ SOUP_SESSION_ERROR,
+ SOUP_SESSION_ERROR_UNSUPPORTED_URI_SCHEME,
+ _("Unsupported URI scheme “%s”"),
+ soup_uri->scheme);
+ g_object_unref (task);
+ }
+}
+
+/**
+ * soup_session_get_finish:
+ * @session: a #SoupSession
+ * @result: the #GAsyncResult passed to your callback
+ * @content_length: (out) (nullable): location to store content length, or %NULL
+ * @content_type: (out) (nullable) (transfer full): location to store content type, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finish an asynchronous operation started by soup_session_get_async().
+ * If the content length is unknown -1 is returned in @content_length.
+ *
+ * Returns: (transfer full): a #GInputStream to read the contents from,
+ * or %NULL in case of error.
+ */
+GInputStream *
+soup_session_get_finish (SoupSession *session,
+ GAsyncResult *result,
+ goffset *content_length,
+ char **content_type,
+ GError **error)
+{
+ GTask *task;
+
+ g_return_val_if_fail (SOUP_IS_SESSION (session), NULL);
+ g_return_val_if_fail (g_task_is_valid (result, session), NULL);
+
+ task = G_TASK (result);
+
+ if (!g_task_had_error (task) && (content_length || content_type)) {
+ SessionGetAsyncData *data;
+
+ data = g_task_get_task_data (task);
+ if (content_length)
+ *content_length = data->content_length;
+ if (content_type) {
+ *content_type = data->content_type;
+ data->content_type = NULL;
+ }
+ }
+
+ return g_task_propagate_pointer (task, error);
+}
+
+static GInputStream *
+soup_session_get_http (SoupSession *session,
+ SoupURI *uri,
+ GCancellable *cancellable,
+ goffset *content_length,
+ char **content_type,
+ GError **error)
+{
+ SoupMessage *msg;
+ GInputStream *stream;
+ SessionGetAsyncData data = { 0, NULL };
+
+ if (!SOUP_URI_VALID_FOR_HTTP (uri)) {
+ char *uri_string = soup_uri_to_string (uri, FALSE);
+
+ g_set_error (error,
+ SOUP_SESSION_ERROR,
+ SOUP_SESSION_ERROR_BAD_URI,
+ _("Invalid “%s” URI: %s"),
+ uri->scheme,
+ uri_string);
+ g_free (uri_string);
+
+ return NULL;
+ }
+
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
+ g_signal_connect (msg, "content-sniffed",
+ G_CALLBACK (get_http_content_sniffed), &data);
+ g_signal_connect (msg, "got-headers",
+ G_CALLBACK (get_http_got_headers), &data);
+ stream = soup_session_send (session, msg, cancellable, error);
+ if (stream) {
+ if (content_length)
+ *content_length = data.content_length;
+ if (content_type) {
+ *content_type = data.content_type;
+ data.content_type = NULL;
+ }
+ }
+
+ g_free (data.content_type);
+
+ return stream;
+}
+
+static GInputStream *
+soup_session_get_file (SoupSession *session,
+ SoupURI *uri,
+ GCancellable *cancellable,
+ goffset *content_length,
+ char **content_type,
+ GError **error)
+{
+ GFile *file;
+ char *path;
+ GFileInfo *info;
+ GInputStream *stream = NULL;
+
+ /* "file:/foo" is not valid, but it must be "file:///..." or "file://localhost/..." */
+ if (!uri->host || (*uri->host && g_ascii_strcasecmp (uri->host, "localhost") != 0)) {
+ char *uri_string = soup_uri_to_string (uri, FALSE);
+
+ g_set_error (error,
+ SOUP_SESSION_ERROR,
+ SOUP_SESSION_ERROR_BAD_URI,
+ _("Invalid “%s” URI: %s"),
+ uri->scheme,
+ uri_string);
+ g_free (uri_string);
+
+ return NULL;
+ }
+
+ path = soup_uri_decode (uri->path);
+#ifdef G_OS_WIN32
+ windowsify_file_uri_path (decoded_path);
+#endif
+
+ if (uri->scheme == SOUP_URI_SCHEME_RESOURCE) {
+ char *uri_string;
+
+ uri_string = g_strdup_printf ("resource://%s", path);
+ file = g_file_new_for_uri (uri_string);
+ g_free (uri_string);
+ } else
+ file = g_file_new_for_path (path);
+ g_free (path);
+
+ info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE ","
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
+ G_FILE_ATTRIBUTE_STANDARD_SIZE,
+ G_FILE_QUERY_INFO_NONE,
+ cancellable, NULL);
+ if (info && g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
+ GFileEnumerator *enumerator;
+
+ enumerator = g_file_enumerate_children (file,
+ "*",
+ G_FILE_QUERY_INFO_NONE,
+ cancellable,
+ error);
+ if (enumerator) {
+ stream = soup_directory_input_stream_new (enumerator, uri);
+ if (content_length)
+ *content_length = -1;
+ if (content_type)
+ *content_type = g_strdup ("text/html");
+
+ g_object_unref (enumerator);
+ }
+
+ g_object_unref (info);
+ g_object_unref (file);
+
+ return stream;
+ }
+
+ if (info) {
+ if (content_length)
+ *content_length = g_file_info_get_size (info);
+
+ if (content_type) {
+ const char *type;
+
+ *content_type = NULL;
+
+ type = g_file_info_get_content_type (info);
+ if (type)
+ *content_type = g_content_type_get_mime_type (type);
+ if (!*content_type)
+ *content_type = g_strdup ("application/octet-stream");
+ }
+
+ g_object_unref (info);
+ }
+
+ stream = G_INPUT_STREAM (g_file_read (file, cancellable, error));
+ g_object_unref (file);
+
+ return stream;
+}
+
+static GInputStream *
+soup_session_get_data (SoupSession *session,
+ SoupURI *uri,
+ GCancellable *cancellable,
+ goffset *content_length,
+ char **content_type,
+ GError **error)
+{
+ GBytes *body;
+ GInputStream *stream;
+
+ if (uri->host != NULL) {
+ char *uri_string = soup_uri_to_string (uri, FALSE);
+
+ g_set_error (error,
+ SOUP_SESSION_ERROR,
+ SOUP_SESSION_ERROR_BAD_URI,
+ _("Invalid “%s” URI: %s"),
+ uri->scheme,
+ uri_string);
+ g_free (uri_string);
+
+ return NULL;
+ }
+
+ body = soup_session_decode_data_uri (session, uri, content_type);
+ if (content_length)
+ *content_length = g_bytes_get_size (body);
+
+ stream = g_memory_input_stream_new_from_bytes (body);
+ g_bytes_unref (body);
+
+ return stream;
+}
+
+/**
+ * soup_session_get:
+ * @session: a #SoupSession
+ * @uri: a URI, in string form
+ * @cancellable: a #GCancellable
+ * @content_length: (out) (nullable): location to store content length, or %NULL
+ * @content_type: (out) (nullable) (transfer full): location to store content type, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Synchronously retrieve @uri and return a #GInputStream to read the contents.
+ * If the content length is unknown -1 is returned in @content_length.
+ *
+ * This function supports several URI schemes (http, https, file, resource and data). If
+ * an unsupported URI is passed it will fail with %SOUP_SESSION_ERROR_UNSUPPORTED_URI_SCHEME
+ * error.
+ *
+ * Returns: (transfer full): a #GInputStream to read the contents from,
+ * or %NULL in case of error.
+ */
+GInputStream *
+soup_session_get (SoupSession *session,
+ const char *uri,
+ GCancellable *cancellable,
+ goffset *content_length,
+ char **content_type,
+ GError **error)
+{
+ SoupURI *soup_uri;
+
+ g_return_val_if_fail (SOUP_IS_SESSION (session), NULL);
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ soup_uri = soup_uri_new (uri);
+ if (!soup_uri) {
+ g_set_error (error,
+ SOUP_SESSION_ERROR,
+ SOUP_SESSION_ERROR_BAD_URI,
+ _("Could not parse URI “%s”"),
+ uri);
+
+ return NULL;
+ }
+
+ if (soup_uri->scheme == SOUP_URI_SCHEME_HTTP || soup_uri->scheme == SOUP_URI_SCHEME_HTTPS)
+ return soup_session_get_http (session, soup_uri, cancellable,
+ content_length, content_type, error);
+ if (soup_uri->scheme == SOUP_URI_SCHEME_FILE || soup_uri->scheme == SOUP_URI_SCHEME_RESOURCE)
+ return soup_session_get_file (session, soup_uri, cancellable,
+ content_length, content_type, error);
+ if (soup_uri->scheme == SOUP_URI_SCHEME_DATA)
+ return soup_session_get_data (session, soup_uri, cancellable,
+ content_length, content_type, error);
+
+ g_set_error (error,
+ SOUP_SESSION_ERROR,
+ SOUP_SESSION_ERROR_UNSUPPORTED_URI_SCHEME,
+ _("Unsupported URI scheme “%s”"),
+ soup_uri->scheme);
+
+ return NULL;
+}
+
+static void
+session_get_async_splice_ready_cb (GOutputStream *ostream,
+ GAsyncResult *result,
+ GTask *task)
+{
+ GError *error = NULL;
+
+ if (g_output_stream_splice_finish (ostream, result, &error) != -1) {
+ g_task_return_pointer (task,
+ g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM
(ostream)),
+ (GDestroyNotify)g_bytes_unref);
+ } else {
+ g_task_return_error (task, error);
+ }
+ g_object_unref (task);
+}
+
+static void
+session_get_async_ready_cb (SoupSession *session,
+ GAsyncResult *result,
+ GTask *task)
+{
+ GInputStream *stream;
+ goffset content_length;
+ char *content_type;
+ GOutputStream *ostream;
+ GError *error = NULL;
+
+ stream = soup_session_get_finish (session, result, &content_length, &content_type, &error);
+ if (!stream) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+
+ return;
+ }
+
+ g_task_set_task_data (task, content_type, g_free);
+
+ if (content_length == 0) {
+ g_task_return_pointer (task,
+ g_bytes_new_static (NULL, 0),
+ (GDestroyNotify)g_bytes_unref);
+ g_object_unref (task);
+ g_object_unref (stream);
+
+ return;
+ }
+
+ ostream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
+ g_output_stream_splice_async (ostream,
+ stream,
+ G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
+ G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
+ g_task_get_priority (task),
+ g_task_get_cancellable (task),
+ (GAsyncReadyCallback)session_get_async_splice_ready_cb,
+ task);
+ g_object_unref (ostream);
+ g_object_unref (stream);
+}
+
+/**
+ * soup_session_get_bytes_async:
+ * @session: a #SoupSession
+ * @uri: a URI, in string form
+ * @io_priority: the I/O priority of the request
+ * @cancellable: a #GCancellable
+ * @callback: the callback to invoke
+ * @user_data: data for @callback
+ *
+ * Asynchronously retrieve @uri to be returned as a #GBytes. This function
+ * is like soup_session_get_async() but the contents are read and returned
+ * as a #GBytes. It should only be used when the resource to be retireved
+ * is not too long and can be stored in memory.
+ *
+ * This function supports several URI schemes (http, https, file, resource and data). If
+ * an unsupported URI is passed it will fail with %SOUP_SESSION_ERROR_UNSUPPORTED_URI_SCHEME
+ * error.
+ *
+ * When the operation is finished, @callback will be called. You can then
+ * call soup_session_get_bytes_finish() to get the result of the operation.
+ */
+void
+soup_session_get_bytes_async (SoupSession *session,
+ const char *uri,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ g_return_if_fail (SOUP_IS_SESSION (session));
+ g_return_if_fail (uri != NULL);
+
+ task = g_task_new (session, cancellable, callback, user_data);
+ g_task_set_priority (task, io_priority);
+ soup_session_get_async (session, uri, io_priority, cancellable,
+ (GAsyncReadyCallback)session_get_async_ready_cb,
+ task);
+}
+
+/**
+ * soup_session_get_bytes_finish:
+ * @session: a #SoupSession
+ * @result: the #GAsyncResult passed to your callback
+ * @content_type: (out) (nullable) (transfer full): location to store content type, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finish an asynchronous operation started by soup_session_get_bytes_async().
+ *
+ * Returns: (transfer full): a #GBytes with the contents, or %NULL in case of error.
+ */
+GBytes *
+soup_session_get_bytes_finish (SoupSession *session,
+ GAsyncResult *result,
+ char **content_type,
+ GError **error)
+{
+ GTask *task;
+
+ g_return_val_if_fail (SOUP_IS_SESSION (session), NULL);
+ g_return_val_if_fail (g_task_is_valid (result, session), NULL);
+
+ task = G_TASK (result);
+
+ if (!g_task_had_error (task) && content_type)
+ *content_type = g_strdup (g_task_get_task_data (task));
+
+ return g_task_propagate_pointer (task, error);
+}
+
+/**
+ * soup_session_get_bytes:
+ * @session: a #SoupSession
+ * @uri: a URI, in string form
+ * @cancellable: a #GCancellable
+ * @content_type: (out) (nullable) (transfer full): location to store content type, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Synchronously retrieve @uri to be returned as a #GBytes. This function
+ * is like soup_session_get() but the contents are read and returned
+ * as a #GBytes. It should only be used when the resource to be retireved
+ * is not too long and can be stored in memory.
+ *
+ * This function supports several URI schemes (http, https, file, resource and data). If
+ * an unsupported URI is passed it will fail with %SOUP_SESSION_ERROR_UNSUPPORTED_URI_SCHEME
+ * error.
+ *
+ * Returns: (transfer full): a #GBytes with the contents, or %NULL in case of error.
+ */
+GBytes *
+soup_session_get_bytes (SoupSession *session,
+ const char *uri,
+ GCancellable *cancellable,
+ char **content_type,
+ GError **error)
+{
+ GInputStream *stream;
+ GOutputStream *ostream;
+ goffset content_length;
+ GBytes *bytes = NULL;
+
+ g_return_val_if_fail (SOUP_IS_SESSION (session), NULL);
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ stream = soup_session_get (session, uri, cancellable, &content_length, content_type, error);
+ if (!stream)
+ return NULL;
+
+ if (content_length == 0) {
+ g_object_unref (stream);
+
+ return g_bytes_new_static (NULL, 0);
+ }
+
+ ostream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
+ if (g_output_stream_splice (ostream,
+ stream,
+ G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
+ G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
+ cancellable, error) != -1) {
+ bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (ostream));
+ }
+ g_object_unref (ostream);
+ g_object_unref (stream);
+
+ return bytes;
+}
+
/**
* soup_session_request:
* @session: a #SoupSession
diff --git a/libsoup/soup-session.h b/libsoup/soup-session.h
index c066212c..9a5a5521 100644
--- a/libsoup/soup-session.h
+++ b/libsoup/soup-session.h
@@ -34,6 +34,17 @@ G_DECLARE_FINAL_TYPE (SoupSession, soup_session, SOUP, SESSION, GObject)
#define SOUP_SESSION_HTTP_ALIASES "http-aliases"
#define SOUP_SESSION_HTTPS_ALIASES "https-aliases"
+SOUP_AVAILABLE_IN_ALL
+GQuark soup_session_error_quark (void);
+#define SOUP_SESSION_ERROR soup_session_error_quark ()
+
+typedef enum {
+ SOUP_SESSION_ERROR_BAD_URI,
+ SOUP_SESSION_ERROR_UNSUPPORTED_URI_SCHEME,
+ SOUP_SESSION_ERROR_PARSING,
+ SOUP_SESSION_ERROR_ENCODING
+} SoupSessionError;
+
SOUP_AVAILABLE_IN_2_42
SoupSession *soup_session_new (void);
@@ -110,6 +121,45 @@ SoupSessionFeature *soup_session_get_feature_for_message(SoupSession *ses
GType feature_type,
SoupMessage *msg);
+SOUP_AVAILABLE_IN_ALL
+GInputStream *soup_session_get (SoupSession *session,
+ const char *uri,
+ GCancellable *cancellable,
+ goffset *content_length,
+ char **content_type,
+ GError **error);
+SOUP_AVAILABLE_IN_ALL
+void soup_session_get_async (SoupSession *session,
+ const char *uri,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+SOUP_AVAILABLE_IN_ALL
+GInputStream *soup_session_get_finish (SoupSession *session,
+ GAsyncResult *result,
+ goffset *content_length,
+ char **content_type,
+ GError **error);
+SOUP_AVAILABLE_IN_ALL
+GBytes *soup_session_get_bytes (SoupSession *session,
+ const char *uri,
+ GCancellable *cancellable,
+ char **content_type,
+ GError **error);
+SOUP_AVAILABLE_IN_ALL
+void soup_session_get_bytes_async (SoupSession *session,
+ const char *uri,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+SOUP_AVAILABLE_IN_ALL
+GBytes *soup_session_get_bytes_finish (SoupSession *session,
+ GAsyncResult *result,
+ char **content_type,
+ GError **error);
+
SOUP_AVAILABLE_IN_2_42
SoupRequest *soup_session_request (SoupSession *session,
const char *uri_string,
diff --git a/tests/session-test.c b/tests/session-test.c
index 1e8d2b14..1417c62e 100644
--- a/tests/session-test.c
+++ b/tests/session-test.c
@@ -2,10 +2,12 @@
#include "test-utils.h"
+static SoupURI *base_uri;
static gboolean server_processed_message;
static gboolean timeout;
static GMainLoop *loop;
static SoupMessagePriority expected_priorities[3];
+static GBytes *index_bytes;
static gboolean
timeout_cb (gpointer user_data)
@@ -31,6 +33,13 @@ server_handler (SoupServer *server,
g_source_set_callback (timer, timeout_cb, &timeout, NULL);
g_source_attach (timer, context);
g_source_unref (timer);
+ } else if (!strcmp (path, "/index.txt")) {
+ soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
+ soup_server_message_set_response (msg, "text/plain",
+ SOUP_MEMORY_STATIC,
+ g_bytes_get_data (index_bytes, NULL),
+ g_bytes_get_size (index_bytes));
+ return;
} else
server_processed_message = TRUE;
@@ -55,7 +64,7 @@ cancel_message_cb (SoupMessage *msg, gpointer session)
}
static void
-do_test_for_session (SoupSession *session, SoupURI *uri,
+do_test_for_session (SoupSession *session,
gboolean queue_is_async,
gboolean send_is_blocking,
gboolean cancel_is_immediate)
@@ -68,14 +77,14 @@ do_test_for_session (SoupSession *session, SoupURI *uri,
debug_printf (1, " queue_message\n");
debug_printf (2, " requesting timeout\n");
- timeout_uri = soup_uri_new_with_base (uri, "/request-timeout");
+ timeout_uri = soup_uri_new_with_base (base_uri, "/request-timeout");
msg = soup_message_new_from_uri ("GET", timeout_uri);
soup_uri_free (timeout_uri);
body = soup_test_session_send (session, msg, NULL, NULL);
g_bytes_unref (body);
g_object_unref (msg);
- msg = soup_message_new_from_uri ("GET", uri);
+ msg = soup_message_new_from_uri ("GET", base_uri);
server_processed_message = timeout = finished = FALSE;
g_signal_connect (msg, "finished",
G_CALLBACK (finished_cb), &finished);
@@ -100,7 +109,7 @@ do_test_for_session (SoupSession *session, SoupURI *uri,
}
debug_printf (1, " send_message\n");
- msg = soup_message_new_from_uri ("GET", uri);
+ msg = soup_message_new_from_uri ("GET", base_uri);
server_processed_message = local_timeout = FALSE;
timeout_id = g_idle_add_full (G_PRIORITY_HIGH, timeout_cb, &local_timeout, NULL);
body = soup_test_session_send (session, msg, NULL, NULL);
@@ -124,7 +133,7 @@ do_test_for_session (SoupSession *session, SoupURI *uri,
return;
debug_printf (1, " cancel_message\n");
- msg = soup_message_new_from_uri ("GET", uri);
+ msg = soup_message_new_from_uri ("GET", base_uri);
finished = FALSE;
g_signal_connect (msg, "finished",
G_CALLBACK (finished_cb), &finished);
@@ -156,13 +165,12 @@ do_test_for_session (SoupSession *session, SoupURI *uri,
}
static void
-do_plain_tests (gconstpointer data)
+do_plain_tests (void)
{
- SoupURI *uri = (SoupURI *)data;
SoupSession *session;
session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
- do_test_for_session (session, uri, TRUE, TRUE, FALSE);
+ do_test_for_session (session, TRUE, TRUE, FALSE);
soup_test_session_abort_unref (session);
}
@@ -183,9 +191,8 @@ priority_test_finished_cb (SoupMessage *msg,
}
static void
-do_priority_tests (gconstpointer data)
+do_priority_tests (void)
{
- SoupURI *uri = (SoupURI *)data;
SoupSession *session;
int i, finished_count = 0;
SoupMessagePriority priorities[] =
@@ -208,7 +215,7 @@ do_priority_tests (gconstpointer data)
char buf[5];
g_snprintf (buf, sizeof (buf), "%d", i);
- msg_uri = soup_uri_new_with_base (uri, buf);
+ msg_uri = soup_uri_new_with_base (base_uri, buf);
msg = soup_message_new_from_uri ("GET", msg_uri);
soup_uri_free (msg_uri);
@@ -369,27 +376,346 @@ do_features_test (void)
soup_test_session_abort_unref (session);
}
+typedef enum {
+ SYNC = 1 << 0,
+ STREAM = 1 << 1
+} GetTestFlags;
+
+typedef struct {
+ GMainLoop *loop;
+ GBytes *body;
+ char *content_type;
+ GError *error;
+} GetAsyncData;
+
+static GBytes *
+stream_to_bytes (GInputStream *stream)
+{
+ GOutputStream *ostream;
+ GBytes *bytes;
+
+ ostream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
+ g_output_stream_splice (ostream,
+ stream,
+ G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
+ G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
+ NULL, NULL);
+ bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (ostream));
+ g_object_unref (ostream);
+
+ return bytes;
+}
+
+static void
+get_async_ready_cb (SoupSession *session,
+ GAsyncResult *result,
+ GetAsyncData *data)
+{
+ GInputStream *stream;
+ goffset content_length;
+
+ stream = soup_session_get_finish (session, result,
+ &content_length,
+ &data->content_type,
+ &data->error);
+ if (stream) {
+ data->body = stream_to_bytes (stream);
+ if (content_length != -1)
+ g_assert_cmpint (g_bytes_get_size (data->body), ==, content_length);
+ g_object_unref (stream);
+ }
+
+ g_main_loop_quit (data->loop);
+}
+
+static void
+get_bytes_async_ready_cb (SoupSession *session,
+ GAsyncResult *result,
+ GetAsyncData *data)
+{
+ data->body = soup_session_get_bytes_finish (session, result,
+ &data->content_type,
+ &data->error);
+ g_main_loop_quit (data->loop);
+}
+
+static void
+do_get_test (SoupSession *session,
+ const char *uri,
+ gboolean stream,
+ gboolean sync,
+ gboolean is_dir)
+{
+ GBytes *body = NULL;
+ char *content_type = NULL;
+ GError *error = NULL;
+
+ if (!sync) {
+ GetAsyncData data;
+ GMainContext *context;
+
+ memset (&data, 0, sizeof (GetAsyncData));
+
+ context = g_main_context_get_thread_default ();
+ data.loop = g_main_loop_new (context, TRUE);
+ if (stream) {
+ soup_session_get_async (session, uri, G_PRIORITY_DEFAULT, NULL,
+ (GAsyncReadyCallback)get_async_ready_cb,
+ &data);
+ } else {
+ soup_session_get_bytes_async (session, uri, G_PRIORITY_DEFAULT, NULL,
+ (GAsyncReadyCallback)get_bytes_async_ready_cb,
+ &data);
+ }
+ g_main_loop_run (data.loop);
+ while (g_main_context_pending (context))
+ g_main_context_iteration (context, FALSE);
+ g_main_loop_unref (data.loop);
+
+ body = data.body;
+ content_type = data.content_type;
+ if (data.error)
+ g_propagate_error (&error, data.error);
+ } else {
+ if (stream) {
+ GInputStream *stream;
+ goffset content_length = 0;
+
+ stream = soup_session_get (session, uri, NULL,
+ &content_length,
+ &content_type,
+ &error);
+ body = stream_to_bytes (stream);
+ if (content_length != -1)
+ g_assert_cmpint (g_bytes_get_size (body), ==, content_length);
+ g_object_unref (stream);
+ } else {
+ body = soup_session_get_bytes (session, uri, NULL,
+ &content_type, &error);
+ }
+ }
+
+ g_assert_no_error (error);
+ g_assert_nonnull (body);
+
+ if (is_dir) {
+ g_assert_cmpstr (content_type, ==, "text/html");
+ g_assert_cmpint (g_bytes_get_size (body), >, 0);
+ } else {
+ g_assert_cmpstr (content_type, ==, "text/plain");
+ g_assert_cmpmem (g_bytes_get_data (body, NULL), g_bytes_get_size (body),
+ g_bytes_get_data (index_bytes, NULL), g_bytes_get_size (index_bytes));
+ }
+
+ g_bytes_unref (body);
+ g_free (content_type);
+}
+
+static void
+do_get_http_test (gconstpointer data)
+{
+ SoupURI *uri;
+ char *uri_string;
+ SoupSession *session;
+ GetTestFlags flags = GPOINTER_TO_UINT (data);
+
+ session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
+
+ uri = soup_uri_new_with_base (base_uri, "/index.txt");
+ uri_string = soup_uri_to_string (uri, FALSE);
+ do_get_test (session, uri_string, flags & STREAM, flags & SYNC, FALSE);
+ g_free (uri_string);
+ soup_uri_free (uri);
+
+ soup_test_session_abort_unref (session);
+}
+
+static void
+do_get_file_test (gconstpointer data)
+{
+ GFile *file;
+ char *uri;
+ SoupSession *session;
+ GetTestFlags flags = GPOINTER_TO_UINT (data);
+
+ session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
+
+ file = g_file_new_for_path (g_test_get_filename (G_TEST_DIST, "index.txt", NULL));
+ uri = g_file_get_uri (file);
+ do_get_test (session, uri, flags & STREAM, flags & SYNC, FALSE);
+ g_free (uri);
+ g_object_unref (file);
+
+ soup_test_session_abort_unref (session);
+}
+
+static void
+do_get_dir_test (gconstpointer data)
+{
+ GFile *file;
+ char *uri;
+ SoupSession *session;
+ GetTestFlags flags = GPOINTER_TO_UINT (data);
+
+ session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
+
+ file = g_file_new_for_path (g_test_get_dir (G_TEST_DIST));
+ uri = g_file_get_uri (file);
+ do_get_test (session, uri, flags & STREAM, flags & SYNC, TRUE);
+ g_free (uri);
+ g_object_unref (file);
+
+ soup_test_session_abort_unref (session);
+}
+
+static void
+do_get_resource_test (gconstpointer data)
+{
+ SoupSession *session;
+ GetTestFlags flags = GPOINTER_TO_UINT (data);
+
+ session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
+
+ do_get_test (session, "resource:///org/gnome/libsoup/tests/index.txt",
+ flags & STREAM, flags & SYNC, FALSE);
+
+ soup_test_session_abort_unref (session);
+}
+
+static void
+do_get_data_test (gconstpointer data)
+{
+ SoupSession *session;
+ char *base64;
+ char *uri;
+ GetTestFlags flags = GPOINTER_TO_UINT (data);
+
+ session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
+
+ base64 = g_base64_encode ((const guchar *)g_bytes_get_data (index_bytes, NULL),
+ g_bytes_get_size (index_bytes));
+ uri = g_strdup_printf ("data:text/plain;base64,%s", base64);
+ do_get_test (session, uri, flags & STREAM, flags & SYNC, FALSE);
+ g_free (uri);
+ g_free (base64);
+
+ soup_test_session_abort_unref (session);
+}
+
+static struct {
+ const char *uri;
+ int expected_error;
+} get_error_tests[] = {
+ { "./foo", SOUP_SESSION_ERROR_BAD_URI },
+ { "http:/localhost/", SOUP_SESSION_ERROR_BAD_URI },
+ { "file://foo/", SOUP_SESSION_ERROR_BAD_URI },
+ { "resource://foo/", SOUP_SESSION_ERROR_BAD_URI },
+ { "data://text/plain,foo", SOUP_SESSION_ERROR_BAD_URI },
+ { "foo://host/path", SOUP_SESSION_ERROR_UNSUPPORTED_URI_SCHEME }
+};
+
+static void
+do_get_error_tests (void)
+{
+ SoupSession *session;
+ guint i;
+
+ session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
+
+ for (i = 0; i < G_N_ELEMENTS (get_error_tests); i++) {
+ GError *error = NULL;
+
+ g_assert_null (soup_session_get (session, get_error_tests[i].uri, NULL, NULL, NULL, &error));
+ g_assert_error (error, SOUP_SESSION_ERROR, get_error_tests[i].expected_error);
+ g_error_free (error);
+ }
+
+ soup_test_session_abort_unref (session);
+}
+
int
main (int argc, char **argv)
{
SoupServer *server;
- SoupURI *uri;
int ret;
test_init (argc, argv, NULL);
server = soup_test_server_new (TRUE);
soup_server_add_handler (server, NULL, server_handler, NULL, NULL);
- uri = soup_test_server_get_uri (server, "http", NULL);
+ base_uri = soup_test_server_get_uri (server, "http", NULL);
+ index_bytes = soup_test_get_index ();
+ soup_test_register_resources ();
- g_test_add_data_func ("/session/SoupSession", uri, do_plain_tests);
- g_test_add_data_func ("/session/priority", uri, do_priority_tests);
+ g_test_add_func ("/session/SoupSession", do_plain_tests);
+ g_test_add_func ("/session/priority", do_priority_tests);
g_test_add_func ("/session/property", do_property_tests);
g_test_add_func ("/session/features", do_features_test);
+ g_test_add_data_func ("/session/get-stream/async/http",
+ GINT_TO_POINTER (STREAM),
+ do_get_http_test);
+ g_test_add_data_func ("/session/get-stream/async/file",
+ GINT_TO_POINTER (STREAM),
+ do_get_file_test);
+ g_test_add_data_func ("/session/get-stream/async/dir",
+ GINT_TO_POINTER (STREAM),
+ do_get_dir_test);
+ g_test_add_data_func ("/session/get-stream/async/resource",
+ GINT_TO_POINTER (STREAM),
+ do_get_resource_test);
+ g_test_add_data_func ("/session/get-stream/async/data",
+ GINT_TO_POINTER (STREAM),
+ do_get_data_test);
+ g_test_add_data_func ("/session/get-stream/sync/http",
+ GINT_TO_POINTER (SYNC | STREAM),
+ do_get_http_test);
+ g_test_add_data_func ("/session/get-stream/sync/file",
+ GINT_TO_POINTER (SYNC | STREAM),
+ do_get_file_test);
+ g_test_add_data_func ("/session/get-stream/sync/dir",
+ GINT_TO_POINTER (SYNC | STREAM),
+ do_get_dir_test);
+ g_test_add_data_func ("/session/get-stream/sync/resource",
+ GINT_TO_POINTER (SYNC | STREAM),
+ do_get_resource_test);
+ g_test_add_data_func ("/session/get-stream/sync/data",
+ GINT_TO_POINTER (SYNC | STREAM),
+ do_get_data_test);
+ g_test_add_data_func ("/session/get-bytes/async/http",
+ GINT_TO_POINTER (0),
+ do_get_http_test);
+ g_test_add_data_func ("/session/get-bytes/async/file",
+ GINT_TO_POINTER (0),
+ do_get_file_test);
+ g_test_add_data_func ("/session/get-bytes/async/dir",
+ GINT_TO_POINTER (0),
+ do_get_dir_test);
+ g_test_add_data_func ("/session/get-bytes/async/resource",
+ GINT_TO_POINTER (0),
+ do_get_resource_test);
+ g_test_add_data_func ("/session/get-bytes/async/data",
+ GINT_TO_POINTER (0),
+ do_get_data_test);
+ g_test_add_data_func ("/session/get-bytes/sync/http",
+ GINT_TO_POINTER (SYNC),
+ do_get_http_test);
+ g_test_add_data_func ("/session/get-bytes/sync/file",
+ GINT_TO_POINTER (SYNC),
+ do_get_file_test);
+ g_test_add_data_func ("/session/get-bytes/sync/dir",
+ GINT_TO_POINTER (SYNC),
+ do_get_dir_test);
+ g_test_add_data_func ("/session/get-bytes/sync/resource",
+ GINT_TO_POINTER (SYNC),
+ do_get_resource_test);
+ g_test_add_data_func ("/session/get-bytes/sync/data",
+ GINT_TO_POINTER (SYNC),
+ do_get_data_test);
+ g_test_add_func ("/session/get/errors", do_get_error_tests);
ret = g_test_run ();
- soup_uri_free (uri);
+ soup_uri_free (base_uri);
soup_test_server_quit_unref (server);
test_cleanup ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]