[libsoup/carlosgc/simple-api: 13/16] 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: 13/16] session: Add new simple API to retrieve a URI
- Date: Mon, 26 Oct 2020 10:55:43 +0000 (UTC)
commit 1c444ee4b9ba612f71621b6ef2370fd8bbd8c676
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 | 511 ++++++++++++++++++++++++++++++++
libsoup/soup-session.h | 50 ++++
tests/session-test.c | 219 +++++++++++++-
4 files changed, 774 insertions(+), 16 deletions(-)
---
diff --git a/docs/reference/libsoup-3.0-sections.txt b/docs/reference/libsoup-3.0-sections.txt
index 05acf88a..a2d65cf3 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_read_uri
+soup_session_read_uri_async
+soup_session_read_uri_finish
+soup_session_load_uri_bytes
+soup_session_load_uri_bytes_async
+soup_session_load_uri_bytes_finish
+<SUBSECTION>
soup_session_websocket_connect_async
soup_session_websocket_connect_finish
<SUBSECTION>
@@ -458,9 +466,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 55541963..581b43d5 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"
@@ -204,6 +205,26 @@ 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.
+ */
+G_DEFINE_QUARK (soup-session-error-quark, soup_session_error)
+
static void
soup_session_init (SoupSession *session)
{
@@ -3637,6 +3658,496 @@ 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);
+}
+
+/**
+ * soup_session_read_uri_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.
+ *
+ * If the given @uri is not HTTP 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_read_uri_finish() to get the result of the operation.
+ */
+void
+soup_session_read_uri_async (SoupSession *session,
+ const char *uri,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ SoupSessionPrivate *priv;
+ GTask *task;
+ SoupURI *soup_uri;
+ SoupMessage *msg;
+ SessionGetAsyncData *data;
+
+ 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;
+ }
+
+ priv = soup_session_get_instance_private (session);
+
+ if (!soup_uri_is_http (soup_uri, priv->http_aliases) &&
+ !soup_uri_is_https (soup_uri, priv->https_aliases)) {
+ 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_uri_free (soup_uri);
+ return;
+ }
+
+ if (!SOUP_URI_VALID_FOR_HTTP (soup_uri)) {
+ g_task_return_new_error (task,
+ SOUP_SESSION_ERROR,
+ SOUP_SESSION_ERROR_BAD_URI,
+ _("Invalid “%s” URI: %s"),
+ soup_uri->scheme,
+ uri);
+ g_object_unref (task);
+ soup_uri_free (soup_uri);
+ return;
+ }
+
+ data = g_slice_new0 (SessionGetAsyncData);
+ g_task_set_task_data (task, data, (GDestroyNotify)session_get_async_data_free);
+
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, soup_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);
+ soup_uri_free (soup_uri);
+}
+
+/**
+ * soup_session_read_uri_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_read_uri_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_read_uri_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);
+}
+
+/**
+ * soup_session_read_uri:
+ * @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.
+ *
+ * If the given @uri is not HTTP 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_read_uri (SoupSession *session,
+ const char *uri,
+ GCancellable *cancellable,
+ goffset *content_length,
+ char **content_type,
+ GError **error)
+{
+ SoupSessionPrivate *priv;
+ SoupURI *soup_uri;
+ SoupMessage *msg;
+ GInputStream *stream;
+ SessionGetAsyncData data = { 0, NULL };
+
+ 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;
+ }
+
+ priv = soup_session_get_instance_private (session);
+
+ if (!soup_uri_is_http (soup_uri, priv->http_aliases) &&
+ !soup_uri_is_https (soup_uri, priv->https_aliases)) {
+ g_set_error (error,
+ SOUP_SESSION_ERROR,
+ SOUP_SESSION_ERROR_UNSUPPORTED_URI_SCHEME,
+ _("Unsupported URI scheme “%s”"),
+ soup_uri->scheme);
+ soup_uri_free (soup_uri);
+
+ return NULL;
+ }
+
+ if (!SOUP_URI_VALID_FOR_HTTP (soup_uri)) {
+ g_set_error (error,
+ SOUP_SESSION_ERROR,
+ SOUP_SESSION_ERROR_BAD_URI,
+ _("Invalid “%s” URI: %s"),
+ soup_uri->scheme,
+ uri);
+ soup_uri_free (soup_uri);
+
+ return NULL;
+ }
+
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, soup_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);
+ soup_uri_free (soup_uri);
+
+ return stream;
+}
+
+static void
+session_load_uri_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_read_uri_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_read_uri_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_load_uri_async_splice_ready_cb,
+ task);
+ g_object_unref (ostream);
+ g_object_unref (stream);
+}
+
+/**
+ * soup_session_load_uri_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_read_uri_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.
+ *
+ * If the given @uri is not HTTP 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_load_uri_bytes_finish() to get the result of the operation.
+ */
+void
+soup_session_load_uri_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_read_uri_async (session, uri, io_priority, cancellable,
+ (GAsyncReadyCallback)session_read_uri_async_ready_cb,
+ task);
+}
+
+/**
+ * soup_session_load_uri_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_load_uri_bytes_async().
+ *
+ * Returns: (transfer full): a #GBytes with the contents, or %NULL in case of error.
+ */
+GBytes *
+soup_session_load_uri_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_load_uri_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_read_uri() 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.
+ *
+ * If the given @uri is not HTTP 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_load_uri_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_read_uri (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..b9d12c66 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_read_uri (SoupSession *session,
+ const char *uri,
+ GCancellable *cancellable,
+ goffset *content_length,
+ char **content_type,
+ GError **error);
+SOUP_AVAILABLE_IN_ALL
+void soup_session_read_uri_async (SoupSession *session,
+ const char *uri,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+SOUP_AVAILABLE_IN_ALL
+GInputStream *soup_session_read_uri_finish (SoupSession *session,
+ GAsyncResult *result,
+ goffset *content_length,
+ char **content_type,
+ GError **error);
+SOUP_AVAILABLE_IN_ALL
+GBytes *soup_session_load_uri_bytes (SoupSession *session,
+ const char *uri,
+ GCancellable *cancellable,
+ char **content_type,
+ GError **error);
+SOUP_AVAILABLE_IN_ALL
+void soup_session_load_uri_bytes_async (SoupSession *session,
+ const char *uri,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+SOUP_AVAILABLE_IN_ALL
+GBytes *soup_session_load_uri_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..baca4a80 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,207 @@ 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
+read_uri_async_ready_cb (SoupSession *session,
+ GAsyncResult *result,
+ GetAsyncData *data)
+{
+ GInputStream *stream;
+ goffset content_length;
+
+ stream = soup_session_read_uri_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
+load_uri_bytes_async_ready_cb (SoupSession *session,
+ GAsyncResult *result,
+ GetAsyncData *data)
+{
+ data->body = soup_session_load_uri_bytes_finish (session, result,
+ &data->content_type,
+ &data->error);
+ g_main_loop_quit (data->loop);
+}
+
+static void
+do_read_uri_test (gconstpointer data)
+{
+ SoupURI *uri;
+ char *uri_string;
+ SoupSession *session;
+ GBytes *body = NULL;
+ char *content_type = NULL;
+ GError *error = NULL;
+ 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);
+
+ if (flags & SYNC) {
+ if (flags & STREAM) {
+ GInputStream *stream;
+ goffset content_length = 0;
+
+ stream = soup_session_read_uri (session, uri_string, 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_load_uri_bytes (session, uri_string, NULL,
+ &content_type, &error);
+ }
+ } else {
+ 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 (flags & STREAM) {
+ soup_session_read_uri_async (session, uri_string, G_PRIORITY_DEFAULT, NULL,
+ (GAsyncReadyCallback)read_uri_async_ready_cb,
+ &data);
+ } else {
+ soup_session_load_uri_bytes_async (session, uri_string, G_PRIORITY_DEFAULT, NULL,
+
(GAsyncReadyCallback)load_uri_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);
+ }
+
+ g_assert_no_error (error);
+ g_assert_nonnull (body);
+ 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);
+ g_free (uri_string);
+ soup_uri_free (uri);
+
+ 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 },
+ { "foo://host/path", SOUP_SESSION_ERROR_UNSUPPORTED_URI_SCHEME }
+};
+
+static void
+do_load_uri_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_load_uri_bytes (session, get_error_tests[i].uri, 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/read-uri/async",
+ GINT_TO_POINTER (STREAM),
+ do_read_uri_test);
+ g_test_add_data_func ("/session/read-uri/sync",
+ GINT_TO_POINTER (SYNC | STREAM),
+ do_read_uri_test);
+ g_test_add_data_func ("/session/load-uri/async",
+ GINT_TO_POINTER (0),
+ do_read_uri_test);
+ g_test_add_data_func ("/session/load-uri/sync",
+ GINT_TO_POINTER (SYNC),
+ do_read_uri_test);
+ g_test_add_func ("/session/load-uri/errors", do_load_uri_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]