[grilo] net: re-structure code
- From: Juan A. Suarez Romero <jasuarez src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [grilo] net: re-structure code
- Date: Wed, 19 Jun 2013 19:29:04 +0000 (UTC)
commit f08caabfb7d4d1aa69eafef294bb55fcb6d65677
Author: Juan A. Suarez Romero <jasuarez igalia com>
Date: Fri Jun 14 19:56:19 2013 +0200
net: re-structure code
As we have rid of stable/unstable code due the new libsoup version
requirement, let's merge some files.
libs/net/Makefile.am | 3 -
libs/net/grl-net-mock.c | 1 -
libs/net/grl-net-private.c | 175 ----------------
libs/net/grl-net-private.h | 95 ---------
libs/net/grl-net-soup.c | 356 ---------------------------------
libs/net/grl-net-wc.c | 471 +++++++++++++++++++++++++++++++++++++++++++-
po/POTFILES.in | 4 +-
7 files changed, 467 insertions(+), 638 deletions(-)
---
diff --git a/libs/net/Makefile.am b/libs/net/Makefile.am
index f4113d1..035477e 100644
--- a/libs/net/Makefile.am
+++ b/libs/net/Makefile.am
@@ -13,8 +13,6 @@ libgrlnet_ GRL_MAJORMINOR@_la_DEPENDENCIES = \
libgrlnet_ GRL_MAJORMINOR@_la_SOURCES = \
grl-net-mock.c \
- grl-net-private.c \
- grl-net-soup.c \
grl-net-wc.c
libgrlnet_ GRL_MAJORMINOR@_la_CFLAGS = \
@@ -46,7 +44,6 @@ libgrlnet_ GRL_MAJORMINOR@include_HEADERS = \
grl-net.h
noinst_HEADERS = \
- grl-net-private.h \
grl-net-mock-private.h
MAINTAINERCLEANFILES = \
diff --git a/libs/net/grl-net-mock.c b/libs/net/grl-net-mock.c
index 6b51e33..3b4c6d7 100644
--- a/libs/net/grl-net-mock.c
+++ b/libs/net/grl-net-mock.c
@@ -35,7 +35,6 @@
#include <grl-log.h>
#include "grl-net-mock-private.h"
-#include "grl-net-private.h"
static GKeyFile *config = NULL;
static GRegex *ignored_parameters = NULL;
diff --git a/libs/net/grl-net-wc.c b/libs/net/grl-net-wc.c
index 95f0640..0490bf8 100644
--- a/libs/net/grl-net-wc.c
+++ b/libs/net/grl-net-wc.c
@@ -39,15 +39,28 @@
#include "config.h"
#endif
-#include <string.h>
+#define LIBSOUP_USE_UNSTABLE_REQUEST_API
+
+#include <errno.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <libsoup/soup-cache.h>
+#include <libsoup/soup-request-http.h>
#include <libsoup/soup.h>
+#include <string.h>
+
+#ifndef LIBSOUP_REQUESTER_DEPRECATED
+#include <libsoup/soup-requester.h>
+#endif
#include <grilo.h>
#include "grl-net-wc.h"
-#include "grl-net-private.h"
#include "grl-net-mock-private.h"
-GRL_LOG_DOMAIN(wc_log_domain);
+#define GRL_LOG_DOMAIN_DEFAULT wc_log_domain
+GRL_LOG_DOMAIN_STATIC(wc_log_domain);
+
+#define GRL_NET_CAPTURE_DIR_VAR "GRL_NET_CAPTURE_DIR"
enum {
PROP_0,
@@ -58,6 +71,32 @@ enum {
PROP_USER_AGENT
};
+struct request_res {
+ SoupRequest *request;
+ gchar *buffer;
+ gsize length;
+ gsize offset;
+};
+
+struct _GrlNetWcPrivate {
+ SoupSession *session;
+ SoupLoggerLogLevel log_level;
+ /* throttling in secs */
+ guint throttling;
+ /* last request time */
+ GTimeVal last_request;
+ /* closure queue for delayed requests */
+ GQueue *pending;
+ /* cache size in Mb */
+ guint cache_size;
+#ifndef LIBSOUP_REQUESTER_DEPRECATED
+ void *requester;
+#endif
+ gchar *previous_data;
+};
+
+static const char *capture_dir = NULL;
+
#define GRL_NET_WC_GET_PRIVATE(object) \
(G_TYPE_INSTANCE_GET_PRIVATE((object), \
GRL_TYPE_NET_WC, \
@@ -165,6 +204,15 @@ grl_net_wc_class_init (GrlNetWcClass *klass)
G_PARAM_STATIC_STRINGS));
}
+static void
+free_op_res (void *op)
+{
+ struct request_res *rr = op;
+
+ g_object_unref (rr->request);
+ g_slice_free (struct request_res, rr);
+}
+
/*
* use-thread-context is available for libsoup-2.4 >= 2.39.0
* We check in run-time if it's available
@@ -181,6 +229,109 @@ set_thread_context (GrlNetWc *self)
}
static void
+init_dump_directory (void)
+{
+ capture_dir = g_getenv (GRL_NET_CAPTURE_DIR_VAR);
+
+ if (capture_dir && is_mocked ()) {
+ GRL_WARNING ("Cannot capture while mocking is enabled.");
+ capture_dir = NULL;
+ return;
+ }
+
+ if (capture_dir && g_mkdir_with_parents (capture_dir, 0700) != 0) {
+ GRL_WARNING ("Could not create capture directory \"%s\": %s",
+ capture_dir, g_strerror (errno));
+ capture_dir = NULL;
+ return;
+ }
+}
+
+static void
+cache_down (GrlNetWc *self)
+{
+ GFile *cache_dir_file;
+ GrlNetWcPrivate *priv = self->priv;
+ SoupSessionFeature *cache = soup_session_get_feature (priv->session, SOUP_TYPE_CACHE);
+ gchar *cache_dir;
+
+ GRL_DEBUG ("cache down");
+
+ if (!cache) {
+ return;
+ }
+
+ soup_cache_clear (SOUP_CACHE (cache));
+
+ g_object_get (cache, "cache-dir", &cache_dir, NULL);
+ cache_dir_file = g_file_new_for_path (cache_dir);
+ g_free (cache_dir);
+
+ g_file_delete (cache_dir_file, NULL, NULL);
+ g_object_unref (G_OBJECT (cache_dir_file));
+
+ soup_session_remove_feature (priv->session, cache);
+}
+
+static void
+cache_up (GrlNetWc *self)
+{
+ SoupCache *cache;
+ GrlNetWcPrivate *priv = self->priv;
+ gchar *dir;
+
+ GRL_DEBUG ("cache up");
+
+ dir = g_dir_make_tmp ("grilo-plugin-cache-XXXXXX", NULL);
+ if (!dir)
+ return;
+
+ cache = soup_cache_new (dir, SOUP_CACHE_SINGLE_USER);
+ g_free (dir);
+
+ soup_session_add_feature (priv->session,
+ SOUP_SESSION_FEATURE (cache));
+
+ if (priv->cache_size) {
+ soup_cache_set_max_size (cache, priv->cache_size * 1024 * 1024);
+ }
+
+ g_object_unref (cache);
+}
+
+static gboolean
+cache_is_available (GrlNetWc *self)
+{
+ return soup_session_get_feature (self->priv->session, SOUP_TYPE_CACHE) != NULL;
+}
+
+static void
+init_requester (GrlNetWc *self)
+{
+#ifndef LIBSOUP_REQUESTER_DEPRECATED
+ GrlNetWcPrivate *priv = self->priv;
+
+ priv->requester = soup_requester_new ();
+ soup_session_add_feature (priv->session,
+ SOUP_SESSION_FEATURE (priv->requester));
+#endif
+ init_dump_directory ();
+}
+
+static void
+finalize_requester (GrlNetWc *self)
+{
+ GrlNetWcPrivate *priv = self->priv;
+
+ cache_down (self);
+ g_free (priv->previous_data);
+
+#ifndef LIBSOUP_REQUESTER_DEPRECATED
+ g_object_unref (priv->requester);
+#endif
+}
+
+static void
grl_net_wc_init (GrlNetWc *wc)
{
GRL_LOG_DOMAIN_INIT (wc_log_domain, "wc");
@@ -267,7 +418,7 @@ grl_net_wc_get_property (GObject *object,
g_value_set_boolean(value, cache_is_available (wc));
break;
case PROP_CACHE_SIZE:
- g_value_set_uint (value, cache_get_size (wc));
+ g_value_set_uint (value, wc->priv->cache_size);
break;
case PROP_USER_AGENT:
g_object_get_property (G_OBJECT (wc->priv->session), "user_agent", value);
@@ -298,6 +449,277 @@ request_clos_destroy (gpointer data)
g_free (c);
}
+static void
+parse_error (guint status,
+ const gchar *reason,
+ const gchar *response,
+ GSimpleAsyncResult *result)
+{
+ if (!response || *response == '\0')
+ response = reason;
+
+ switch (status) {
+ case SOUP_STATUS_CANT_RESOLVE:
+ case SOUP_STATUS_CANT_CONNECT:
+ case SOUP_STATUS_SSL_FAILED:
+ case SOUP_STATUS_IO_ERROR:
+ g_simple_async_result_set_error (result, GRL_NET_WC_ERROR,
+ GRL_NET_WC_ERROR_NETWORK_ERROR,
+ _("Cannot connect to the server"));
+ return;
+ case SOUP_STATUS_CANT_RESOLVE_PROXY:
+ case SOUP_STATUS_CANT_CONNECT_PROXY:
+ g_simple_async_result_set_error (result, GRL_NET_WC_ERROR,
+ GRL_NET_WC_ERROR_PROXY_ERROR,
+ _("Cannot connect to the proxy server"));
+ return;
+ case SOUP_STATUS_INTERNAL_SERVER_ERROR: /* 500 */
+ case SOUP_STATUS_MALFORMED:
+ case SOUP_STATUS_BAD_REQUEST: /* 400 */
+ g_simple_async_result_set_error (result, GRL_NET_WC_ERROR,
+ GRL_NET_WC_ERROR_PROTOCOL_ERROR,
+ _("Invalid request URI or header: %s"),
+ response);
+ return;
+ case SOUP_STATUS_UNAUTHORIZED: /* 401 */
+ case SOUP_STATUS_FORBIDDEN: /* 403 */
+ g_simple_async_result_set_error (result, GRL_NET_WC_ERROR,
+ GRL_NET_WC_ERROR_AUTHENTICATION_REQUIRED,
+ _("Authentication required: %s"), response);
+ return;
+ case SOUP_STATUS_NOT_FOUND: /* 404 */
+ g_simple_async_result_set_error (result, GRL_NET_WC_ERROR,
+ GRL_NET_WC_ERROR_NOT_FOUND,
+ _("The requested resource was not found: %s"),
+ response);
+ return;
+ case SOUP_STATUS_CONFLICT: /* 409 */
+ case SOUP_STATUS_PRECONDITION_FAILED: /* 412 */
+ g_simple_async_result_set_error (result, GRL_NET_WC_ERROR,
+ GRL_NET_WC_ERROR_CONFLICT,
+ _("The entry has been modified since it was downloaded: %s"),
+ response);
+ return;
+ case SOUP_STATUS_CANCELLED:
+ g_simple_async_result_set_error (result, GRL_NET_WC_ERROR,
+ GRL_NET_WC_ERROR_CANCELLED,
+ _("Operation was cancelled"));
+ return;
+ default:
+ g_message (_("Unhandled status: %s"), soup_status_get_phrase (status));
+ }
+}
+
+static char *
+build_request_filename (const char *uri)
+{
+ char *hash = g_compute_checksum_for_string (G_CHECKSUM_MD5, uri, -1);
+
+ char *filename = g_strdup_printf ("%"G_GINT64_FORMAT "-%s.data",
+ g_get_monotonic_time (), hash);
+
+ g_free (hash);
+ return filename;
+}
+
+static void
+dump_data (SoupURI *uri,
+ const char *buffer,
+ const gsize length)
+{
+ if (!capture_dir)
+ return;
+
+ char *uri_string = soup_uri_to_string (uri, FALSE);
+
+ /* Write request content to file in capture directory. */
+ char *request_filename = build_request_filename (uri_string);
+ char *path = g_build_filename (capture_dir, request_filename, NULL);
+
+ GError *error = NULL;
+ if (!g_file_set_contents (path, buffer, length, &error)) {
+ GRL_WARNING ("Could not write contents to disk: %s", error->message);
+ g_error_free (error);
+ }
+
+ g_free (path);
+
+ /* Append record about the just written file to "grl-net-mock-data-%PID.ini"
+ * in the capture directory. */
+ char *filename = g_strdup_printf ("grl-net-mock-data-%u.ini", getpid());
+ path = g_build_filename (capture_dir, filename, NULL);
+ g_free (filename);
+
+ FILE *stream = g_fopen (path, "at");
+ g_free (path);
+
+ if (!stream) {
+ GRL_WARNING ("Could not write contents to disk: %s", g_strerror (errno));
+ } else {
+ if (ftell (stream) == 0)
+ fprintf (stream, "[default]\nversion=%d\n\n", GRL_NET_MOCK_VERSION);
+
+ fprintf (stream, "[%s]\ndata=%s\n\n", uri_string, request_filename);
+ fclose (stream);
+ }
+
+ g_free (request_filename);
+ g_free (uri_string);
+}
+
+static void
+read_async_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data);
+ struct request_res *rr = g_simple_async_result_get_op_res_gpointer (result);;
+
+ GError *error = NULL;
+ gssize s = g_input_stream_read_finish (G_INPUT_STREAM (source), res, &error);
+
+ gsize to_read;
+
+ if (s > 0) {
+ /* Continue reading */
+ rr->offset += s;
+ to_read = rr->length - rr->offset;
+
+ if (!to_read) {
+ /* Buffer is not enough; we need to assign more space */
+ rr->length *= 2;
+ rr->buffer = g_renew (gchar, rr->buffer, rr->length);
+ to_read = rr->length - rr->offset;
+ }
+
+ g_input_stream_read_async (G_INPUT_STREAM (source),
+ rr->buffer + rr->offset,
+ to_read,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ read_async_cb,
+ user_data);
+ return;
+ }
+
+ /* Put the end of string */
+ rr->buffer[rr->offset] = '\0';
+
+ g_input_stream_close (G_INPUT_STREAM (source), NULL, NULL);
+
+ if (error) {
+ if (error->code == G_IO_ERROR_CANCELLED) {
+ g_simple_async_result_set_error (result, GRL_NET_WC_ERROR,
+ GRL_NET_WC_ERROR_CANCELLED,
+ _("Operation was cancelled"));
+ } else {
+ g_simple_async_result_set_error (result, GRL_NET_WC_ERROR,
+ GRL_NET_WC_ERROR_UNAVAILABLE,
+ _("Data not available"));
+ }
+
+ g_error_free (error);
+
+ g_simple_async_result_complete (result);
+ g_object_unref (result);
+ return;
+ }
+
+ {
+ SoupMessage *msg =
+ soup_request_http_get_message (SOUP_REQUEST_HTTP (rr->request));
+
+ if (msg && msg->status_code != SOUP_STATUS_OK) {
+ parse_error (msg->status_code,
+ msg->reason_phrase,
+ msg->response_body->data,
+ G_SIMPLE_ASYNC_RESULT (user_data));
+ g_object_unref (msg);
+ }
+ }
+
+ g_simple_async_result_complete (result);
+ g_object_unref (result);
+}
+
+static void
+reply_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data);
+ struct request_res *rr = g_simple_async_result_get_op_res_gpointer (result);
+
+ GError *error = NULL;
+ GInputStream *in = soup_request_send_finish (rr->request, res, &error);
+
+ if (error) {
+ g_simple_async_result_set_error (result, GRL_NET_WC_ERROR,
+ GRL_NET_WC_ERROR_UNAVAILABLE,
+ _("Data not available"));
+ g_error_free (error);
+
+ g_simple_async_result_complete (result);
+ g_object_unref (result);
+ return;
+ }
+
+ rr->length = soup_request_get_content_length (rr->request) + 1;
+ if (rr->length == 1)
+ rr->length = 50 * 1024;
+
+ rr->buffer = g_new (gchar, rr->length);
+
+ g_input_stream_read_async (in,
+ rr->buffer,
+ rr->length,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ read_async_cb,
+ user_data);
+}
+
+static void
+get_url_now (GrlNetWc *self,
+ const char *url,
+ GHashTable *headers,
+ GAsyncResult *result,
+ GCancellable *cancellable)
+{
+ GrlNetWcPrivate *priv = self->priv;
+ struct request_res *rr = g_slice_new0 (struct request_res);
+
+ g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result),
+ rr,
+ NULL);
+
+#ifdef LIBSOUP_REQUESTER_DEPRECATED
+ SoupURI *uri = soup_uri_new (url);
+ rr->request = soup_session_request_uri (priv->session, uri, NULL);
+ soup_uri_free (uri);
+#else
+ rr->request = soup_requester_request (priv->requester, url, NULL);
+#endif
+
+ if (headers != NULL) {
+ SoupMessage *message;
+ GHashTableIter iter;
+ const char *key, *value;
+
+ message = soup_request_http_get_message (SOUP_REQUEST_HTTP (rr->request));
+
+ if (message) {
+ g_hash_table_iter_init (&iter, headers);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *)&value)) {
+ soup_message_headers_append (message->request_headers, key, value);
+ }
+ g_object_unref (message);
+ }
+ }
+
+ soup_request_send_async (rr->request, cancellable, reply_cb, result);
+}
+
static gboolean
get_url_cb (gpointer user_data)
{
@@ -357,6 +779,36 @@ get_url (GrlNetWc *self,
g_queue_push_head (self->priv->pending, c);
}
+static void
+get_content (GrlNetWc *self,
+ void *op,
+ gchar **content,
+ gsize *length)
+{
+ GrlNetWcPrivate *priv = self->priv;
+ struct request_res *rr = op;
+
+ dump_data (soup_request_get_uri (rr->request),
+ rr->buffer,
+ rr->offset);
+
+ if (priv->previous_data)
+ g_free (priv->previous_data);
+
+ priv->previous_data = rr->buffer;
+
+ if (content)
+ *content = self->priv->previous_data;
+ else {
+ g_free (rr->buffer);
+ self->priv->previous_data = NULL;
+ rr->buffer = NULL;
+ }
+
+ if (length)
+ *length = rr->offset;
+}
+
/**
* grl_net_wc_new:
*
@@ -637,7 +1089,16 @@ grl_net_wc_set_cache_size (GrlNetWc *self,
{
g_return_if_fail (GRL_IS_NET_WC (self));
- cache_set_size (self, size);
+ if (self->priv->cache_size == size)
+ return;
+
+ self->priv->cache_size = size;
+
+ SoupSessionFeature *cache = soup_session_get_feature (self->priv->session, SOUP_TYPE_CACHE);
+ if (!cache)
+ return;
+
+ soup_cache_set_max_size (SOUP_CACHE (cache), size * 1024 * 1024);
}
/**
diff --git a/po/POTFILES.in b/po/POTFILES.in
index e682287..8d0b471 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,7 +1,5 @@
libs/net/grl-net-mock.c
-libs/net/grl-net-private.c
-libs/net/grl-net-soup-stable.c
-libs/net/grl-net-soup-unstable.c
+libs/net/grl-net-wc.c
src/grilo.c
src/grl-multiple.c
src/grl-registry.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]