[gupnp] [PATCH 1/2] Enable gzip compression for large action response bodies
- From: Sven Neumann <s neumann raumfeld com>
- To: gupnp o-hand com
- Cc: Sven Neumann <s neumann raumfeld com>
- Subject: [gupnp] [PATCH 1/2] Enable gzip compression for large action response bodies
- Date: Fri, 17 Sep 2010 11:08:24 +0200
Enable transparent decoding of gzip compressed HTTP bodies in
libsoup and let GUPnPServiceProxy set the Accept-Encoding header
to "gzip".
Let GUPnPService check for the Accept-Encoding header and
optionally compress large (> 1024 bytes) repsonse bodies. This
saves some bandwidth and gives a noticeable speedup on slow
connections.
---
libgupnp/gupnp-context.c | 3 ++
libgupnp/gupnp-service-proxy.c | 4 +++
libgupnp/gupnp-service.c | 44 +++++++++++++++++++++++++++------
libgupnp/http-headers.c | 53 ++++++++++++++++++++++++++++++++++++++++
libgupnp/http-headers.h | 5 ++++
5 files changed, 101 insertions(+), 8 deletions(-)
diff --git a/libgupnp/gupnp-context.c b/libgupnp/gupnp-context.c
index 13fa0d3..457d37c 100644
--- a/libgupnp/gupnp-context.c
+++ b/libgupnp/gupnp-context.c
@@ -158,6 +158,9 @@ gupnp_context_constructor (GType type,
SOUP_SESSION_FEATURE (logger));
}
+ 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 d5707fc..06008b5 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 64a5ca8..ee0c5a1 100644
--- a/libgupnp/gupnp-service.c
+++ b/libgupnp/gupnp-service.c
@@ -193,6 +193,7 @@ struct _GUPnPServiceAction {
char *name;
SoupMessage *msg;
+ gboolean accept_gzip;
GUPnPXMLDoc *doc;
xmlNode *node;
@@ -252,7 +253,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,
@@ -273,13 +273,22 @@ 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->accept_gzip && action->response_str->len > 1024) {
+ 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
@@ -873,6 +882,7 @@ control_server_handler (SoupServer *server,
xmlDoc *doc;
xmlNode *action_node;
const char *soap_action;
+ const char *accept_encoding;
char *action_name;
char *end;
GUPnPServiceAction *action;
@@ -938,7 +948,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);
@@ -949,6 +959,24 @@ control_server_handler (SoupServer *server,
soap_action);
action->context = g_object_ref (context);
+ /* Get accepted encodings */
+ accept_encoding = soup_message_headers_get_list (msg->request_headers,
+ "Accept-Encoding");
+
+ if (accept_encoding) {
+ GSList *codings;
+
+ codings = soup_header_parse_quality_list (accept_encoding,
+ NULL);
+ if (codings &&
+ g_slist_find_custom (codings, "gzip",
+ (GCompareFunc) g_ascii_strcasecmp)) {
+ action->accept_gzip = TRUE;
+ }
+
+ soup_header_free_list (codings);
+ }
+
/* Tell soup server that response is not ready yet */
soup_server_pause_message (server, msg);
diff --git a/libgupnp/http-headers.c b/libgupnp/http-headers.c
index 9b14868..4c06b77 100644
--- a/libgupnp/http-headers.c
+++ b/libgupnp/http-headers.c
@@ -354,3 +354,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..507adf5 100644
--- a/libgupnp/http-headers.h
+++ b/libgupnp/http-headers.h
@@ -54,6 +54,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__ */
--
1.7.0.4
--
To unsubscribe send a mail to gupnp+unsubscribe\@o-hand.com
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]