souphttp*: add ability to do HTTP session logging
authorReynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
Wed, 8 Jan 2014 02:00:56 +0000 (23:00 -0300)
committerReynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
Tue, 11 Feb 2014 20:50:44 +0000 (17:50 -0300)
This changeset adds the loggin infrastructure and
mods both souphttpsrc and souphttclientsink to use it.

https://bugzilla.gnome.org/show_bug.cgi?id=721764

ext/soup/Makefile.am
ext/soup/gstsoup.c
ext/soup/gstsouphttpclientsink.c
ext/soup/gstsouphttpclientsink.h
ext/soup/gstsouphttpsrc.c
ext/soup/gstsouphttpsrc.h
ext/soup/gstsouputils.c [new file with mode: 0644]
ext/soup/gstsouputils.h [new file with mode: 0644]

index e34fe87866067f645e63827a9a9726686d014407..c1bd73571e0727cb5dd77b56db337f7025b53cd5 100644 (file)
@@ -1,6 +1,6 @@
 plugin_LTLIBRARIES = libgstsouphttpsrc.la
 
-libgstsouphttpsrc_la_SOURCES = gstsouphttpsrc.c gstsouphttpclientsink.c gstsoup.c
+libgstsouphttpsrc_la_SOURCES = gstsouphttpsrc.c gstsouphttpclientsink.c gstsouputils.c gstsoup.c
 
 libgstsouphttpsrc_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \
        $(GST_CFLAGS) $(SOUP_CFLAGS) \
@@ -10,4 +10,4 @@ libgstsouphttpsrc_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgsttag-@GST_API_VERSION
 libgstsouphttpsrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 libgstsouphttpsrc_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
 
-noinst_HEADERS = gstsouphttpsrc.h gstsouphttpclientsink.h
+noinst_HEADERS = gstsouphttpsrc.h gstsouphttpclientsink.h gstsouputils.h
index e12ca18f4136b5cca959798808e364b7615bb88b..10bdba7480f87a66020f490f2e05f59257b2eaa5 100644 (file)
@@ -20,7 +20,9 @@
 
 #include "gstsouphttpsrc.h"
 #include "gstsouphttpclientsink.h"
+#include "gstsouputils.h"
 
+GST_DEBUG_CATEGORY (soup_utils_debug);
 
 static gboolean
 plugin_init (GstPlugin * plugin)
@@ -36,6 +38,7 @@ plugin_init (GstPlugin * plugin)
       GST_TYPE_SOUP_HTTP_SRC);
   gst_element_register (plugin, "souphttpclientsink", GST_RANK_NONE,
       GST_TYPE_SOUP_HTTP_CLIENT_SINK);
+  GST_DEBUG_CATEGORY_INIT (soup_utils_debug, "souputils", 0, "Soup utils");
 
   return TRUE;
 }
index f1b9c0dee3556113d023366f0a785b7111e06571..904d71c4c2f9f150e82905e359c039614d08bf34 100644 (file)
@@ -41,6 +41,7 @@
 #include <gst/gst.h>
 #include <gst/base/gstbasesink.h>
 #include "gstsouphttpclientsink.h"
+#include "gstsouputils.h"
 
 #include <gst/glib-compat-private.h>
 
@@ -93,10 +94,12 @@ enum
   PROP_PROXY_ID,
   PROP_PROXY_PW,
   PROP_COOKIES,
-  PROP_SESSION
+  PROP_SESSION,
+  PROP_SOUP_LOG_LEVEL
 };
 
 #define DEFAULT_USER_AGENT           "GStreamer souphttpclientsink "
+#define DEFAULT_SOUP_LOG_LEVEL       SOUP_LOGGER_LOG_NONE
 
 /* pad templates */
 
@@ -168,6 +171,19 @@ gst_soup_http_client_sink_class_init (GstSoupHttpClientSinkClass * klass)
   g_object_class_install_property (gobject_class, PROP_COOKIES,
       g_param_spec_boxed ("cookies", "Cookies", "HTTP request cookies",
           G_TYPE_STRV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+   * GstSoupHttpClientSink::http-log-level:
+   *
+   * If set and > 0, captures and dumps HTTP session data as
+   * log messages if log level >= GST_LEVEL_TRACE
+   *
+   * Since: 1.4
+   */
+  g_object_class_install_property (gobject_class, PROP_SOUP_LOG_LEVEL,
+      g_param_spec_enum ("http-log-level", "HTTP log level",
+          "Set log level for soup's HTTP session log",
+          SOUP_TYPE_LOGGER_LOG_LEVEL, DEFAULT_SOUP_LOG_LEVEL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   gst_element_class_add_pad_template (gstelement_class,
       gst_static_pad_template_get (&gst_soup_http_client_sink_sink_template));
@@ -214,6 +230,7 @@ gst_soup_http_client_sink_init (GstSoupHttpClientSink * souphttpsink)
   souphttpsink->proxy_pw = NULL;
   souphttpsink->prop_session = NULL;
   souphttpsink->timeout = 1;
+  souphttpsink->log_level = DEFAULT_SOUP_LOG_LEVEL;
   proxy = g_getenv ("http_proxy");
   if (proxy && !gst_soup_http_client_sink_set_proxy (souphttpsink, proxy)) {
     GST_WARNING_OBJECT (souphttpsink,
@@ -316,6 +333,9 @@ gst_soup_http_client_sink_set_property (GObject * object, guint property_id,
       g_strfreev (souphttpsink->cookies);
       souphttpsink->cookies = g_strdupv (g_value_get_boxed (value));
       break;
+    case PROP_SOUP_LOG_LEVEL:
+      souphttpsink->log_level = g_value_get_enum (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -368,6 +388,9 @@ gst_soup_http_client_sink_get_property (GObject * object, guint property_id,
     case PROP_COOKIES:
       g_value_set_boxed (value, g_strdupv (souphttpsink->cookies));
       break;
+    case PROP_SOUP_LOG_LEVEL:
+      g_value_set_enum (value, souphttpsink->log_level);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -514,13 +537,14 @@ gst_soup_http_client_sink_start (GstBaseSink * sink)
         souphttpsink->user_agent, SOUP_SESSION_TIMEOUT, souphttpsink->timeout,
         NULL);
 
-    //soup_session_add_feature (souphttpsink->session,
-    //    SOUP_SESSION_FEATURE (soup_logger_new (SOUP_LOGGER_LOG_BODY, 100)));
-
     g_signal_connect (souphttpsink->session, "authenticate",
         G_CALLBACK (authenticate), souphttpsink);
   }
 
+  /* Set up logging */
+  gst_soup_util_log_setup (souphttpsink->session, souphttpsink->log_level,
+      GST_ELEMENT (souphttpsink));
+
   return TRUE;
 }
 
index 5c7dda62faabb67c24344f39ba1bc5b6ab3367cf..a33027523f3c48f9fa44fcb0106ac6b0ed91392c 100644 (file)
@@ -66,7 +66,7 @@ struct _GstSoupHttpClientSink
   char *user_agent;
   gboolean automatic_redirect;
   gchar **cookies;
-
+  SoupLoggerLogLevel log_level;
 };
 
 struct _GstSoupHttpClientSinkClass
index 7c4e7e872abf149a0c0ecdd291b3c2aa88122302..b5fa7d89f378eb339ed8a205b301c2dec02510de 100644 (file)
@@ -79,6 +79,7 @@
 #include <gst/gst-i18n-plugin.h>
 #include <libsoup/soup.h>
 #include "gstsouphttpsrc.h"
+#include "gstsouputils.h"
 
 #include <gst/tag/tag.h>
 
@@ -105,11 +106,13 @@ enum
   PROP_COOKIES,
   PROP_IRADIO_MODE,
   PROP_TIMEOUT,
-  PROP_EXTRA_HEADERS
+  PROP_EXTRA_HEADERS,
+  PROP_SOUP_LOG_LEVEL
 };
 
 #define DEFAULT_USER_AGENT           "GStreamer souphttpsrc "
 #define DEFAULT_IRADIO_MODE          TRUE
+#define DEFAULT_SOUP_LOG_LEVEL       SOUP_LOGGER_LOG_NONE
 
 static void gst_soup_http_src_uri_handler_init (gpointer g_iface,
     gpointer iface_data);
@@ -243,6 +246,19 @@ gst_soup_http_src_class_init (GstSoupHTTPSrcClass * klass)
           "Enable internet radio mode (ask server to send shoutcast/icecast "
           "metadata interleaved with the actual stream data)",
           DEFAULT_IRADIO_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+   * GstSoupHTTPSrc::http-log-level:
+   *
+   * If set and > 0, captures and dumps HTTP session data as
+   * log messages if log level >= GST_LEVEL_TRACE
+   *
+   * Since: 1.4
+   */
+  g_object_class_install_property (gobject_class, PROP_SOUP_LOG_LEVEL,
+      g_param_spec_enum ("http-log-level", "HTTP log level",
+          "Set log level for soup's HTTP session log",
+          SOUP_TYPE_LOGGER_LOG_LEVEL, DEFAULT_SOUP_LOG_LEVEL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   gst_element_class_add_pad_template (gstelement_class,
       gst_static_pad_template_get (&srctemplate));
@@ -313,6 +329,7 @@ gst_soup_http_src_init (GstSoupHTTPSrc * src)
   src->context = NULL;
   src->session = NULL;
   src->msg = NULL;
+  src->log_level = DEFAULT_SOUP_LOG_LEVEL;
   proxy = g_getenv ("http_proxy");
   if (proxy && !gst_soup_http_src_set_proxy (src, proxy)) {
     GST_WARNING_OBJECT (src,
@@ -438,6 +455,9 @@ gst_soup_http_src_set_property (GObject * object, guint prop_id,
       src->extra_headers = s ? gst_structure_copy (s) : NULL;
       break;
     }
+    case PROP_SOUP_LOG_LEVEL:
+      src->log_level = g_value_get_enum (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -499,6 +519,9 @@ gst_soup_http_src_get_property (GObject * object, guint prop_id,
     case PROP_EXTRA_HEADERS:
       gst_value_set_structure (value, src->extra_headers);
       break;
+    case PROP_SOUP_LOG_LEVEL:
+      g_value_set_enum (value, src->log_level);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -695,6 +718,10 @@ gst_soup_http_src_session_open (GstSoupHTTPSrc * src)
 
   g_signal_connect (src->session, "authenticate",
       G_CALLBACK (gst_soup_http_src_authenticate_cb), src);
+
+  /* Set up logging */
+  gst_soup_util_log_setup (src->session, src->log_level, GST_ELEMENT (src));
+
   return TRUE;
 }
 
@@ -725,13 +752,6 @@ gst_soup_http_src_authenticate_cb (SoupSession * session, SoupMessage * msg,
   }
 }
 
-static void
-gst_soup_http_src_headers_foreach (const gchar * name, const gchar * val,
-    gpointer src)
-{
-  GST_DEBUG_OBJECT (src, " %s: %s", name, val);
-}
-
 static void
 gst_soup_http_src_got_headers_cb (SoupMessage * msg, GstSoupHTTPSrc * src)
 {
@@ -741,9 +761,7 @@ gst_soup_http_src_got_headers_cb (SoupMessage * msg, GstSoupHTTPSrc * src)
   guint64 newsize;
   GHashTable *params = NULL;
 
-  GST_DEBUG_OBJECT (src, "got headers:");
-  soup_message_headers_foreach (msg->response_headers,
-      gst_soup_http_src_headers_foreach, src);
+  GST_INFO_OBJECT (src, "got headers");
 
   if (msg->status_code == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED &&
       src->proxy_id && src->proxy_pw)
@@ -1251,10 +1269,6 @@ gst_soup_http_src_build_message (GstSoupHTTPSrc * src, const gchar * method)
 
   gst_soup_http_src_add_extra_headers (src);
 
-  GST_DEBUG_OBJECT (src, "request headers:");
-  soup_message_headers_foreach (src->msg->request_headers,
-      gst_soup_http_src_headers_foreach, src);
-
   return TRUE;
 }
 
index 8ebd2b612d39a8bb78deb2b597220b93763c4e52..162a01674239e908b34e06702ad9606a3f105ce1 100644 (file)
@@ -83,6 +83,7 @@ struct _GstSoupHTTPSrc {
                                 * decide if an out of range request should be
                                 * handled as an error or EOS when the content
                                 * size is unknown */
+  SoupLoggerLogLevel log_level;/* Soup HTTP session logger level */
 
   /* Shoutcast/icecast metadata extraction handling. */
   gboolean iradio_mode;
diff --git a/ext/soup/gstsouputils.c b/ext/soup/gstsouputils.c
new file mode 100644 (file)
index 0000000..2f06a76
--- /dev/null
@@ -0,0 +1,97 @@
+/* GStreamer
+ *
+ * Copyright (C) 2014 Samsung Electronics. All rights reserved.
+ *     @Author: Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more
+ */
+
+
+#include <glib.h>
+#include <gst/gst.h>
+#include <libsoup/soup.h>
+#include "gstsouputils.h"
+
+/**
+ * Soup logger funcs
+ */
+
+GST_DEBUG_CATEGORY_EXTERN (soup_utils_debug);
+#define GST_CAT_DEFAULT soup_utils_debug
+
+static inline gchar
+gst_soup_util_log_make_level_tag (SoupLoggerLogLevel level)
+{
+  gchar c;
+
+  if (G_UNLIKELY (level > 9))
+    return '?';
+
+  switch (level) {
+    case SOUP_LOGGER_LOG_MINIMAL:
+      c = 'M';
+      break;
+    case SOUP_LOGGER_LOG_HEADERS:
+      c = 'H';
+      break;
+    case SOUP_LOGGER_LOG_BODY:
+      c = 'B';
+      break;
+    default:
+      /* Unknown level. If this is hit libsoup likely added a new
+       * log level to SoupLoggerLogLevel and it should be added
+       * as a case */
+      c = level + '0';
+      break;
+  }
+  return c;
+}
+
+static void
+gst_soup_util_log_printer_cb (SoupLogger G_GNUC_UNUSED * logger,
+    SoupLoggerLogLevel level, char direction, const char *data,
+    gpointer user_data)
+{
+  gchar c;
+  c = gst_soup_util_log_make_level_tag (level);
+  GST_TRACE_OBJECT (GST_ELEMENT (user_data), "HTTP_SESSION(%c): %c %s", c,
+      direction, data);
+}
+
+void
+gst_soup_util_log_setup (SoupSession * session, SoupLoggerLogLevel level,
+    GstElement * element)
+{
+  SoupLogger *logger;
+
+  if (!level) {
+    GST_INFO_OBJECT (element, "Not attaching a logger with level 0");
+    return;
+  }
+
+  g_assert (session && element);
+
+  if (gst_debug_category_get_threshold (GST_CAT_DEFAULT)
+      < GST_LEVEL_TRACE) {
+    GST_INFO_OBJECT (element, "Not setting up HTTP session logger. "
+        "Need at least GST_LEVEL_TRACE");
+    return;
+  }
+
+  /* Create a new logger and set body_size_limit to -1 (no limit) */
+  logger = soup_logger_new (level, -1);
+  soup_logger_set_printer (logger, gst_soup_util_log_printer_cb,
+      gst_object_ref (element), (GDestroyNotify) gst_object_unref);
+
+  /* Attach logger to session */
+  soup_session_add_feature (session, SOUP_SESSION_FEATURE (logger));
+  g_object_unref (logger);
+}
diff --git a/ext/soup/gstsouputils.h b/ext/soup/gstsouputils.h
new file mode 100644 (file)
index 0000000..e73525d
--- /dev/null
@@ -0,0 +1,31 @@
+/* GStreamer
+ *
+ * Copyright (C) 2014 Samsung Electronics. All rights reserved.
+ *     @Author: Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more
+ */
+
+#ifndef __GST_SOUP_UTILS_H__
+#define __GST_SOUP_UTILS_H__
+
+#include <glib.h>
+#include <gst/gst.h>
+#include <libsoup/soup.h>
+
+G_BEGIN_DECLS
+
+void gst_soup_util_log_setup (SoupSession * session, SoupLoggerLogLevel level,
+    GstElement * element);
+
+G_END_DECLS
+
+#endif