From 4f42fff349df98733e6e40cb848e604d8e93b329 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Tue, 7 Jan 2014 23:00:56 -0300 Subject: [PATCH] souphttp*: add ability to do HTTP session logging 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 | 4 +- ext/soup/gstsoup.c | 3 ++ ext/soup/gstsouphttpclientsink.c | 32 +++++++++++-- ext/soup/gstsouphttpclientsink.h | 2 +- ext/soup/gstsouphttpsrc.c | 44 +++++++++++------- ext/soup/gstsouphttpsrc.h | 1 + ext/soup/gstsouputils.c | 97 ++++++++++++++++++++++++++++++++++++++++ ext/soup/gstsouputils.h | 31 +++++++++++++ 8 files changed, 192 insertions(+), 22 deletions(-) create mode 100644 ext/soup/gstsouputils.c create mode 100644 ext/soup/gstsouputils.h diff --git a/ext/soup/Makefile.am b/ext/soup/Makefile.am index e34fe87..c1bd735 100644 --- a/ext/soup/Makefile.am +++ b/ext/soup/Makefile.am @@ -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 diff --git a/ext/soup/gstsoup.c b/ext/soup/gstsoup.c index e12ca18..10bdba7 100644 --- a/ext/soup/gstsoup.c +++ b/ext/soup/gstsoup.c @@ -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; } diff --git a/ext/soup/gstsouphttpclientsink.c b/ext/soup/gstsouphttpclientsink.c index f1b9c0d..904d71c 100644 --- a/ext/soup/gstsouphttpclientsink.c +++ b/ext/soup/gstsouphttpclientsink.c @@ -41,6 +41,7 @@ #include #include #include "gstsouphttpclientsink.h" +#include "gstsouputils.h" #include @@ -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; } diff --git a/ext/soup/gstsouphttpclientsink.h b/ext/soup/gstsouphttpclientsink.h index 5c7dda6..a330275 100644 --- a/ext/soup/gstsouphttpclientsink.h +++ b/ext/soup/gstsouphttpclientsink.h @@ -66,7 +66,7 @@ struct _GstSoupHttpClientSink char *user_agent; gboolean automatic_redirect; gchar **cookies; - + SoupLoggerLogLevel log_level; }; struct _GstSoupHttpClientSinkClass diff --git a/ext/soup/gstsouphttpsrc.c b/ext/soup/gstsouphttpsrc.c index 7c4e7e8..b5fa7d8 100644 --- a/ext/soup/gstsouphttpsrc.c +++ b/ext/soup/gstsouphttpsrc.c @@ -79,6 +79,7 @@ #include #include #include "gstsouphttpsrc.h" +#include "gstsouputils.h" #include @@ -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; } @@ -726,13 +753,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) { const char *value; @@ -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; } diff --git a/ext/soup/gstsouphttpsrc.h b/ext/soup/gstsouphttpsrc.h index 8ebd2b6..162a016 100644 --- a/ext/soup/gstsouphttpsrc.h +++ b/ext/soup/gstsouphttpsrc.h @@ -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 index 0000000..2f06a76 --- /dev/null +++ b/ext/soup/gstsouputils.c @@ -0,0 +1,97 @@ +/* GStreamer + * + * Copyright (C) 2014 Samsung Electronics. All rights reserved. + * @Author: Reynaldo H. Verdejo Pinochet + * + * 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 +#include +#include +#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 index 0000000..e73525d --- /dev/null +++ b/ext/soup/gstsouputils.h @@ -0,0 +1,31 @@ +/* GStreamer + * + * Copyright (C) 2014 Samsung Electronics. All rights reserved. + * @Author: Reynaldo H. Verdejo Pinochet + * + * 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 +#include +#include + +G_BEGIN_DECLS + +void gst_soup_util_log_setup (SoupSession * session, SoupLoggerLogLevel level, + GstElement * element); + +G_END_DECLS + +#endif -- 2.7.4