Re: [gupnp] enable gzip compression for action responses



Hi,

to keep the ball rolling, here's an updated patch that bumps the
required versions of glib and libsoup. It also includes some code
cleanup. The parsing of the Accept-Encoding header moved to the
http-headers utilities and it is now delayed until the action response
is being constructed.

Run-time configuration is still missing...


Sven


diff --git a/configure.ac b/configure.ac
index 664b89b..f53e959 100644
--- a/configure.ac
+++ b/configure.ac
@@ -15,11 +15,11 @@ AC_CONFIG_MACRO_DIR([m4])
 AC_FUNC_MMAP
 AC_SYS_LARGEFILE
 
-PKG_CHECK_MODULES(LIBGUPNP, glib-2.0 >= 2.18 \
-                            gobject-2.0 >= 2.18 \
+PKG_CHECK_MODULES(LIBGUPNP, glib-2.0 >= 2.24.0 \
+                            gio-2.0 \
                             gmodule-2.0 \
                             gssdp-1.0 >= 0.7.1 \
-                            libsoup-2.4 >= 2.4.1 \
+                            libsoup-2.4 >= 2.28.2 \
                             libxml-2.0 \
                             uuid)
 
diff --git a/libgupnp/gupnp-context.c b/libgupnp/gupnp-context.c
index 62aa4e9..268b198 100644
--- a/libgupnp/gupnp-context.c
+++ b/libgupnp/gupnp-context.c
@@ -157,6 +157,9 @@ gupnp_context_constructor (GType                  type,
 		soup_logger_attach (logger, context->priv->session);
 	}
 
+        soup_session_add_feature_by_type (context->priv->session,
+                                          SOUP_TYPE_CONTENT_DECODER);
+
 	return object;
 }
 
diff --git a/libgupnp/gupnp-service-proxy.c b/libgupnp/gupnp-service-proxy.c
index c548e2d..1ca8584 100644
--- a/libgupnp/gupnp-service-proxy.c
+++ b/libgupnp/gupnp-service-proxy.c
@@ -700,6 +700,10 @@ begin_action_msg (GUPnPServiceProxy              *proxy,
         /* Specify language */
         http_request_set_accept_language (ret->msg);
 
+        /* Accept gzip encoding */
+        soup_message_headers_append (ret->msg->request_headers,
+				     "Accept-Encoding", "gzip");
+
         /* Set up envelope */
         ret->msg_str = xml_util_new_string ();
 
diff --git a/libgupnp/gupnp-service.c b/libgupnp/gupnp-service.c
index 0e1ea16..827f76f 100644
--- a/libgupnp/gupnp-service.c
+++ b/libgupnp/gupnp-service.c
@@ -250,7 +250,6 @@ static void
 finalize_action (GUPnPServiceAction *action)
 {
         SoupServer *server;
-        char *response_body;
 
         /* Embed action->response_str in a SOAP document */
         g_string_prepend (action->response_str,
@@ -271,13 +270,23 @@ finalize_action (GUPnPServiceAction *action)
                          "</s:Body>"
                          "</s:Envelope>");
 
-        response_body = g_string_free (action->response_str, FALSE);
+        soup_message_headers_replace (action->msg->response_headers,
+                                      "Content-Type",
+                                      "text/xml; charset=\"utf-8\"");
 
-        soup_message_set_response (action->msg,
-                                   "text/xml; charset=\"utf-8\"",
-                                   SOUP_MEMORY_TAKE,
-                                   response_body,
-                                   strlen (response_body));
+        if (action->response_str->len > 1024 &&
+            http_request_get_accept_gzip_encoding (action->msg)) {
+                http_response_set_body_gzip (action->msg,
+                                             action->response_str->str,
+                                             action->response_str->len);
+                g_string_free (action->response_str, TRUE);
+        } else {
+                soup_message_body_append (action->msg->response_body,
+                                          SOUP_MEMORY_TAKE,
+                                          action->response_str->str,
+                                          action->response_str->len);
+                g_string_free (action->response_str, FALSE);
+        }
 
         /* Server header on response */
         soup_message_headers_append
@@ -938,7 +947,7 @@ control_server_handler (SoupServer        *server,
         }
 
         /* Create action structure */
-        action = g_slice_new (GUPnPServiceAction);
+        action = g_slice_new0 (GUPnPServiceAction);
 
         action->ref_count    = 1;
         action->name         = g_strdup (action_name);
diff --git a/libgupnp/http-headers.c b/libgupnp/http-headers.c
index 3e10e40..096f7d4 100644
--- a/libgupnp/http-headers.c
+++ b/libgupnp/http-headers.c
@@ -283,6 +283,32 @@ http_request_get_accept_locales (SoupMessage *message)
         return locales;
 }
 
+/* Check if "gzip" is in the Accept-Encoding header. */
+G_GNUC_INTERNAL gboolean
+http_request_get_accept_gzip_encoding (SoupMessage *msg)
+{
+        const char *accept_encoding;
+        GSList *codings;
+        gboolean accept_gzip = FALSE;
+
+        accept_encoding = soup_message_headers_get_list (msg->request_headers,
+                                                         "Accept-Encoding");
+
+        if (accept_encoding == NULL)
+                return FALSE;
+
+        codings = soup_header_parse_quality_list (accept_encoding, NULL);
+
+        if (g_slist_find_custom (codings, "gzip",
+                                 (GCompareFunc) g_ascii_strcasecmp)) {
+                accept_gzip = TRUE;
+        }
+
+        soup_header_free_list (codings);
+
+        return accept_gzip;
+}
+
 /* Set Accept-Language header according to @locale. */
 void
 http_response_set_content_locale (SoupMessage *msg,
@@ -349,3 +375,56 @@ http_response_set_content_range (SoupMessage  *msg,
 
         g_free (content_range);
 }
+
+/* Set Content-Encoding header to gzip and append compressed body */
+void
+http_response_set_body_gzip (SoupMessage *msg,
+                             const char  *body,
+                             const gsize  length)
+{
+        GZlibCompressor *compressor;
+        gboolean finished = FALSE;
+        gsize converted = 0;
+
+        soup_message_headers_append (msg->response_headers,
+                                     "Content-Encoding", "gzip");
+
+        compressor = g_zlib_compressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP, -1);
+
+        while (! finished) {
+                GError *error = NULL;
+                char buf[65536];
+                gsize bytes_read = 0;
+                gsize bytes_written = 0;
+
+                switch (g_converter_convert (G_CONVERTER (compressor),
+                                             body + converted,
+                                             length - converted,
+                                             buf, sizeof (buf),
+                                             G_CONVERTER_INPUT_AT_END,
+                                             &bytes_read, &bytes_written,
+                                             &error)) {
+                case G_CONVERTER_ERROR:
+                        g_warning ("Error compressing response: %s",
+                                   error->message);
+                        g_error_free (error);
+                        g_object_unref (compressor);
+                        return;
+                case G_CONVERTER_CONVERTED:
+                        converted += bytes_read;
+                        break;
+                case G_CONVERTER_FINISHED:
+                        finished = TRUE;
+                        break;
+                case G_CONVERTER_FLUSHED:
+                        break;
+                }
+
+                if (bytes_written)
+                        soup_message_body_append (msg->response_body,
+                                                  SOUP_MEMORY_COPY,
+                                                  buf, bytes_written);
+        }
+
+        g_object_unref (compressor);
+}
diff --git a/libgupnp/http-headers.h b/libgupnp/http-headers.h
index 6dbaa94..a8be780 100644
--- a/libgupnp/http-headers.h
+++ b/libgupnp/http-headers.h
@@ -22,7 +22,7 @@
 #ifndef __HTTP_HEADERS_H__
 #define __HTTP_HEADERS_H__
 
-#include <libsoup/soup-message.h>
+#include <libsoup/soup.h>
 
 G_BEGIN_DECLS
 
@@ -38,6 +38,9 @@ http_request_set_accept_language (SoupMessage  *message);
 G_GNUC_INTERNAL GList *
 http_request_get_accept_locales  (SoupMessage  *message);
 
+G_GNUC_INTERNAL gboolean
+http_request_get_accept_gzip_encoding (SoupMessage *msg);
+
 G_GNUC_INTERNAL void
 http_response_set_content_locale (SoupMessage  *message,
                                   const char   *locale);
@@ -54,6 +57,11 @@ http_response_set_content_range  (SoupMessage  *message,
                                   gsize         length,
                                   gsize         total);
 
+G_GNUC_INTERNAL void
+http_response_set_body_gzip      (SoupMessage   *msg,
+                                  const char    *body,
+                                  const gsize    length);
+
 G_END_DECLS
 
 #endif /* __HTTP_HEADERS_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]