[gupnp/wip/phako/libsoup3] Initial port to libsoup3 API
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gupnp/wip/phako/libsoup3] Initial port to libsoup3 API
- Date: Mon, 26 Jul 2021 21:30:20 +0000 (UTC)
commit 5248162f915fc7915b728b7adb54cc669e18db5b
Author: Jens Georg <mail jensge org>
Date: Mon Jul 26 23:30:01 2021 +0200
Initial port to libsoup3 API
libgupnp/gupnp-acl-private.h | 6 +-
libgupnp/gupnp-acl.c | 6 +-
libgupnp/gupnp-context-manager.c | 3 +-
libgupnp/gupnp-context-private.h | 4 +-
libgupnp/gupnp-context.c | 211 +++++++-------
libgupnp/gupnp-control-point.c | 62 +++--
libgupnp/gupnp-device-info.c | 17 +-
libgupnp/gupnp-device-info.h | 3 +-
libgupnp/gupnp-device-proxy.c | 4 +-
libgupnp/gupnp-device.c | 4 +-
libgupnp/gupnp-error.c | 8 +-
libgupnp/gupnp-resource-factory-private.h | 8 +-
libgupnp/gupnp-resource-factory.c | 8 +-
libgupnp/gupnp-root-device.c | 17 +-
libgupnp/gupnp-service-info.c | 44 +--
libgupnp/gupnp-service-info.h | 3 +-
libgupnp/gupnp-service-private.h | 2 +-
libgupnp/gupnp-service-proxy-action-private.h | 1 +
libgupnp/gupnp-service-proxy-action.c | 21 +-
libgupnp/gupnp-service-proxy.c | 318 +++++++++++++--------
libgupnp/gupnp-service.c | 380 +++++++++++++++-----------
libgupnp/gupnp-service.h | 2 +-
libgupnp/gupnp-unix-context-manager.c | 1 -
libgupnp/http-headers.c | 25 +-
libgupnp/http-headers.h | 8 +-
libgupnp/xml-util.c | 19 +-
libgupnp/xml-util.h | 7 +-
meson.build | 8 +-
tests/test-bugs.c | 17 +-
tests/test-context.c | 67 +++--
30 files changed, 734 insertions(+), 550 deletions(-)
---
diff --git a/libgupnp/gupnp-acl-private.h b/libgupnp/gupnp-acl-private.h
index f243569..0a10f47 100644
--- a/libgupnp/gupnp-acl-private.h
+++ b/libgupnp/gupnp-acl-private.h
@@ -43,10 +43,9 @@ typedef struct _AclServerHandler
typedef struct _AclAsyncHandler
{
SoupServer *server;
- SoupMessage *message;
+ SoupServerMessage *message;
char *path;
GHashTable *query;
- SoupClientContext *client;
AclServerHandler *handler;
} AclAsyncHandler;
@@ -62,10 +61,9 @@ acl_server_handler_free (AclServerHandler *handler);
G_GNUC_INTERNAL AclAsyncHandler *
acl_async_handler_new (SoupServer *server,
- SoupMessage *message,
+ SoupServerMessage *message,
const char *path,
GHashTable *query,
- SoupClientContext *client,
AclServerHandler *handler);
G_GNUC_INTERNAL void
diff --git a/libgupnp/gupnp-acl.c b/libgupnp/gupnp-acl.c
index ff8c4f9..e7f7e88 100644
--- a/libgupnp/gupnp-acl.c
+++ b/libgupnp/gupnp-acl.c
@@ -219,10 +219,9 @@ acl_server_handler_free (AclServerHandler *handler)
*/
AclAsyncHandler *
acl_async_handler_new (SoupServer *server,
- SoupMessage *message,
+ SoupServerMessage *message,
const char *path,
GHashTable *query,
- SoupClientContext *client,
AclServerHandler *handler)
{
AclAsyncHandler *data = g_slice_new0 (AclAsyncHandler);
@@ -232,7 +231,6 @@ acl_async_handler_new (SoupServer *server,
data->path = g_strdup (path);
if (query != NULL)
data->query = g_hash_table_ref (query);
- data->client = g_boxed_copy (SOUP_TYPE_CLIENT_CONTEXT, client);
data->handler = handler;
return data;
@@ -253,7 +251,7 @@ acl_async_handler_free (AclAsyncHandler *handler)
g_free (handler->path);
if (handler->query != NULL)
g_hash_table_unref (handler->query);
- g_boxed_free (SOUP_TYPE_CLIENT_CONTEXT, handler->client);
+ //g_boxed_free (SOUP_TYPE_CLIENT_CONTEXT, handler->client);
g_slice_free (AclAsyncHandler, handler);
}
diff --git a/libgupnp/gupnp-context-manager.c b/libgupnp/gupnp-context-manager.c
index 534899d..66bfca0 100644
--- a/libgupnp/gupnp-context-manager.c
+++ b/libgupnp/gupnp-context-manager.c
@@ -29,7 +29,6 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
-#include <libsoup/soup-address.h>
#include <glib.h>
#include <glib/gstdio.h>
@@ -493,7 +492,7 @@ gupnp_context_manager_class_init (GUPnPContextManagerClass *klass)
g_param_spec_uint ("port",
"Port",
"Port to create contexts for",
- 0, G_MAXUINT, SOUP_ADDRESS_ANY_PORT,
+ 0, G_MAXUINT, 0,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_NAME |
diff --git a/libgupnp/gupnp-context-private.h b/libgupnp/gupnp-context-private.h
index e5cd507..2259582 100644
--- a/libgupnp/gupnp-context-private.h
+++ b/libgupnp/gupnp-context-private.h
@@ -15,7 +15,7 @@
G_BEGIN_DECLS
-G_GNUC_INTERNAL SoupURI *
+G_GNUC_INTERNAL GUri *
_gupnp_context_get_server_uri (GUPnPContext *context);
G_GNUC_INTERNAL void
@@ -23,7 +23,7 @@ _gupnp_context_add_server_handler_with_data (GUPnPContext *context,
const char *path,
AclServerHandler *data);
-G_GNUC_INTERNAL SoupURI *
+G_GNUC_INTERNAL GUri *
gupnp_context_rewrite_uri_to_uri (GUPnPContext *context,
const char *uri);
diff --git a/libgupnp/gupnp-context.c b/libgupnp/gupnp-context.c
index efec13f..45fe816 100644
--- a/libgupnp/gupnp-context.c
+++ b/libgupnp/gupnp-context.c
@@ -36,7 +36,6 @@
#endif
#include <sys/types.h>
#include <sys/stat.h>
-#include <libsoup/soup-address.h>
#include <glib/gstdio.h>
#include "gupnp-acl.h"
@@ -52,10 +51,9 @@
static void
gupnp_acl_server_handler (SoupServer *server,
- SoupMessage *msg,
+ SoupServerMessage *msg,
const char *path,
GHashTable *query,
- SoupClientContext *client,
gpointer user_data);
static void
@@ -70,7 +68,7 @@ struct _GUPnPContextPrivate {
SoupSession *session;
SoupServer *server; /* Started on demand */
- SoupURI *server_uri;
+ GUri *server_uri;
char *default_language;
GList *host_path_datas;
@@ -189,15 +187,13 @@ gupnp_context_initable_init (GInitable *initable,
user_agent = g_strdup_printf ("%s GUPnP/" VERSION " DLNADOC/1.50",
g_get_prgname ()? : "");
- g_object_set (priv->session,
- SOUP_SESSION_USER_AGENT,
- user_agent,
- NULL);
+
+ soup_session_set_user_agent (priv->session, user_agent);
g_free (user_agent);
if (g_getenv ("GUPNP_DEBUG")) {
SoupLogger *logger;
- logger = soup_logger_new (SOUP_LOGGER_LOG_BODY, -1);
+ logger = soup_logger_new (SOUP_LOGGER_LOG_BODY);
soup_session_add_feature (priv->session,
SOUP_SESSION_FEATURE (logger));
}
@@ -349,7 +345,7 @@ gupnp_context_finalize (GObject *object)
g_free (priv->default_language);
if (priv->server_uri)
- soup_uri_free (priv->server_uri);
+ g_uri_unref (priv->server_uri);
/* Call super */
object_class = G_OBJECT_CLASS (gupnp_context_parent_class);
@@ -418,7 +414,7 @@ gupnp_context_class_init (GUPnPContextClass *klass)
g_param_spec_uint ("port",
"Port",
"Port to run on",
- 0, G_MAXUINT, SOUP_ADDRESS_ANY_PORT,
+ 0, G_MAXUINT, 0,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_NAME |
@@ -549,13 +545,12 @@ gupnp_context_get_session (GUPnPContext *context)
**/
static void
default_server_handler (G_GNUC_UNUSED SoupServer *server,
- SoupMessage *msg,
+ SoupServerMessage *msg,
G_GNUC_UNUSED const char *path,
G_GNUC_UNUSED GHashTable *query,
- G_GNUC_UNUSED SoupClientContext *client,
G_GNUC_UNUSED gpointer user_data)
{
- soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);
+ soup_server_message_set_status (msg, SOUP_STATUS_NOT_FOUND, "Not found");
}
/**
@@ -621,21 +616,21 @@ gupnp_context_get_server (GUPnPContext *context)
/*
* Makes a SoupURI that refers to our server.
**/
-static SoupURI *
+static GUri *
make_server_uri (GUPnPContext *context)
{
SoupServer *server = gupnp_context_get_server (context);
GSList *uris = soup_server_get_uris (server);
if (uris)
{
- SoupURI *uri = soup_uri_copy (uris->data);
- g_slist_free_full (uris, (GDestroyNotify) soup_uri_free);
+ GUri *uri = g_uri_ref (uris->data);
+ g_slist_free_full (uris, (GDestroyNotify) g_uri_unref);
return uri;
}
return NULL;
}
-SoupURI *
+GUri *
_gupnp_context_get_server_uri (GUPnPContext *context)
{
GUPnPContextPrivate *priv;
@@ -645,7 +640,7 @@ _gupnp_context_get_server_uri (GUPnPContext *context)
priv->server_uri = make_server_uri (context);
if (priv->server_uri)
- return soup_uri_copy (priv->server_uri);
+ return g_uri_ref (priv->server_uri);
return NULL;
}
@@ -694,7 +689,7 @@ gupnp_context_get_port (GUPnPContext *context)
if (priv->server_uri == NULL)
priv->server_uri = make_server_uri (context);
- return soup_uri_get_port (priv->server_uri);
+ return g_uri_get_port (priv->server_uri);
}
/**
@@ -891,17 +886,17 @@ append_locale (const char *local_path, GList *locales)
/* Redirect @msg to the same URI, but with a slash appended. */
static void
-redirect_to_folder (SoupMessage *msg)
+redirect_to_folder (SoupServerMessage *msg)
{
char *uri, *redir_uri;
- uri = soup_uri_to_string (soup_message_get_uri (msg),
- FALSE);
+ uri = g_uri_to_string_partial (soup_server_message_get_uri (msg), G_URI_HIDE_PASSWORD);
redir_uri = g_strdup_printf ("%s/", uri);
- soup_message_headers_append (msg->response_headers,
+ soup_message_headers_append (soup_server_message_get_response_headers (msg),
"Location", redir_uri);
- soup_message_set_status (msg,
- SOUP_STATUS_MOVED_PERMANENTLY);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_MOVED_PERMANENTLY,
+ "Moved permanently");
g_free (redir_uri);
g_free (uri);
}
@@ -931,10 +926,9 @@ update_client_cache (GUPnPContext *context,
* '..' as libsoup does this for us. */
static void
host_path_handler (G_GNUC_UNUSED SoupServer *server,
- SoupMessage *msg,
+ SoupServerMessage *msg,
const char *path,
G_GNUC_UNUSED GHashTable *query,
- SoupClientContext *client_ctx,
gpointer user_data)
{
char *local_path, *path_to_open;
@@ -953,9 +947,9 @@ host_path_handler (G_GNUC_UNUSED SoupServer *server,
path_to_open = NULL;
host_path_data = (HostPathData *) user_data;
- if (msg->method != SOUP_METHOD_GET &&
- msg->method != SOUP_METHOD_HEAD) {
- soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
+ if (soup_server_message_get_method (msg) != SOUP_METHOD_GET &&
+ soup_server_message_get_method (msg) != SOUP_METHOD_HEAD) {
+ soup_server_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED, "Not implemented");
goto DONE;
}
@@ -964,16 +958,16 @@ host_path_handler (G_GNUC_UNUSED SoupServer *server,
* Also set Connection: close header, since the request originated
* from a HTTP 1.0 client
*/
- if (soup_message_get_http_version (msg) == SOUP_HTTP_1_0) {
- soup_message_set_http_version (msg, SOUP_HTTP_1_1);
- soup_message_headers_append (msg->response_headers,
+ if (soup_server_message_get_http_version (msg) == SOUP_HTTP_1_0) {
+ soup_server_message_set_http_version (msg, SOUP_HTTP_1_1);
+ soup_message_headers_append (soup_server_message_get_response_headers (msg),
"Connection",
"close");
}
- user_agent = soup_message_headers_get_one (msg->request_headers,
+ user_agent = soup_message_headers_get_one (soup_server_message_get_request_headers (msg),
"User-Agent");
- host = soup_client_context_get_host (client_ctx);
+ host = soup_server_message_get_remote_host (msg);
/* If there was no User-Agent in the request, try to guess from the
* discovery message and put it into the response headers for further
@@ -985,7 +979,7 @@ host_path_handler (G_GNUC_UNUSED SoupServer *server,
user_agent = gssdp_client_guess_user_agent (client, host);
if (user_agent != NULL) {
- soup_message_headers_append (msg->response_headers,
+ soup_message_headers_append (soup_server_message_get_response_headers (msg),
"User-Agent",
user_agent);
}
@@ -996,13 +990,13 @@ host_path_handler (G_GNUC_UNUSED SoupServer *server,
/* Construct base local path */
local_path = construct_local_path (path, user_agent, host_path_data);
if (!local_path) {
- soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
+ soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, "Bad request");
goto DONE;
}
/* Get preferred locales */
- orig_locales = locales = http_request_get_accept_locales (msg);
+ orig_locales = locales = http_request_get_accept_locales (soup_server_message_get_request_headers
(msg));
AGAIN:
/* Add locale suffix if available */
@@ -1011,7 +1005,7 @@ host_path_handler (G_GNUC_UNUSED SoupServer *server,
/* See what we've got */
if (g_stat (path_to_open, &st) == -1) {
if (errno == EPERM)
- soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
+ soup_server_message_set_status (msg, SOUP_STATUS_FORBIDDEN, "Forbidden");
else if (errno == ENOENT) {
if (locales) {
g_free (path_to_open);
@@ -1020,11 +1014,12 @@ host_path_handler (G_GNUC_UNUSED SoupServer *server,
goto AGAIN;
} else
- soup_message_set_status (msg,
- SOUP_STATUS_NOT_FOUND);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_NOT_FOUND,
+ "Not found");
} else
- soup_message_set_status
- (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
+ soup_server_message_set_status
+ (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR, "Internal server error");
goto DONE;
}
@@ -1059,25 +1054,36 @@ host_path_handler (G_GNUC_UNUSED SoupServer *server,
g_error_free (error);
- soup_message_set_status (msg,
- SOUP_STATUS_INTERNAL_SERVER_ERROR);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_INTERNAL_SERVER_ERROR, "Internal server error");
goto DONE;
}
/* Handle method (GET or HEAD) */
status = SOUP_STATUS_OK;
+ SoupMessageHeaders *response_headers = soup_server_message_get_response_headers (msg);
+ SoupMessageHeaders *request_headers = soup_server_message_get_request_headers (msg);
+
+ /* Add requested content */
+ // Creating the buffer here regardless of whether we use it.
+ // It will take ownership of the mapped file and we can unref it on exit
+ // This will prevent leaking the mapped file in other cases
+ GBytes *buffer = g_bytes_new_with_free_func (g_mapped_file_get_contents (mapped_file),
+ g_mapped_file_get_length (mapped_file),
+ (GDestroyNotify) g_mapped_file_unref,
+ mapped_file);
- if (msg->method == SOUP_METHOD_GET) {
+
+ if (soup_server_message_get_method (msg)== SOUP_METHOD_GET) {
gboolean have_range;
- SoupBuffer *buffer;
SoupRange *ranges;
int nranges;
/* Find out range */
have_range = FALSE;
- if (soup_message_headers_get_ranges (msg->request_headers,
+ if (soup_message_headers_get_ranges (request_headers,
st.st_size,
&ranges,
&nranges))
@@ -1089,90 +1095,86 @@ host_path_handler (G_GNUC_UNUSED SoupServer *server,
st.st_size < 0 ||
ranges[0].start >= st.st_size ||
ranges[0].start > ranges[0].end)) {
- soup_message_set_status
+ soup_server_message_set_status
(msg,
- SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE);
- soup_message_headers_free_ranges (msg->request_headers,
+ SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE,
+ "Range not satisfyable");
+ soup_message_headers_free_ranges (request_headers,
ranges);
goto DONE;
}
- /* Add requested content */
- buffer = soup_buffer_new_with_owner
- (g_mapped_file_get_contents (mapped_file),
- g_mapped_file_get_length (mapped_file),
- mapped_file,
- (GDestroyNotify) g_mapped_file_unref);
+ SoupMessageBody *message_body = soup_server_message_get_response_body (msg);
/* Set range and status */
if (have_range) {
- SoupBuffer *range_buffer;
+ GBytes *range_buffer;
- soup_message_body_truncate (msg->response_body);
+ soup_message_body_truncate (message_body);
soup_message_headers_set_content_range (
- msg->response_headers,
+ response_headers,
ranges[0].start,
ranges[0].end,
- buffer->length);
- range_buffer = soup_buffer_new_subbuffer (
- buffer,
+ g_bytes_get_size (buffer));
+ range_buffer = g_bytes_new_from_bytes (buffer,
ranges[0].start,
ranges[0].end - ranges[0].start + 1);
- soup_message_body_append_buffer (msg->response_body,
- range_buffer);
+ soup_message_body_append_bytes (message_body,
+ range_buffer);
status = SOUP_STATUS_PARTIAL_CONTENT;
- soup_message_headers_free_ranges (msg->request_headers,
+ soup_message_headers_free_ranges (request_headers,
ranges);
- soup_buffer_free (range_buffer);
+ g_bytes_unref (range_buffer);
} else
- soup_message_body_append_buffer (msg->response_body, buffer);
+ soup_message_body_append_bytes (message_body, buffer);
- soup_buffer_free (buffer);
- } else if (msg->method == SOUP_METHOD_HEAD) {
+ } else if (soup_server_message_get_method (msg) == SOUP_METHOD_HEAD) {
char *length;
- length = g_strdup_printf ("%lu", (gulong) st.st_size);
- soup_message_headers_append (msg->response_headers,
+ length = g_strdup_printf ("%zu", st.st_size);
+ soup_message_headers_append (response_headers,
"Content-Length",
length);
g_free (length);
} else {
- soup_message_set_status (msg,
- SOUP_STATUS_METHOD_NOT_ALLOWED);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_METHOD_NOT_ALLOWED,
+ "Method not allowed");
goto DONE;
}
/* Set Content-Type */
- http_response_set_content_type (msg,
- path_to_open,
+ http_response_set_content_type (response_headers,
+ path_to_open,
(guchar *) g_mapped_file_get_contents
(mapped_file),
st.st_size);
/* Set Content-Language */
if (locales)
- http_response_set_content_locale (msg, locales->data);
- else if (soup_message_headers_get_one (msg->request_headers,
+ http_response_set_content_locale (response_headers, locales->data);
+ else if (soup_message_headers_get_one (request_headers,
"Accept-Language")) {
- soup_message_headers_append (msg->response_headers,
+ soup_message_headers_append (response_headers,
"Content-Language",
host_path_data->default_language);
}
/* Set Accept-Ranges */
- soup_message_headers_append (msg->response_headers,
+ soup_message_headers_append (response_headers,
"Accept-Ranges",
"bytes");
/* Set status */
- soup_message_set_status (msg, status);
+ soup_server_message_set_status (msg, status, NULL);
DONE:
/* Cleanup */
+ g_bytes_unref (buffer);
g_free (path_to_open);
g_free (local_path);
@@ -1428,13 +1430,12 @@ gupnp_acl_async_callback (GUPnPAcl *acl,
allowed = gupnp_acl_is_allowed_finish (acl, res, &error);
soup_server_unpause_message (data->server, data->message);
if (!allowed)
- soup_message_set_status (data->message, SOUP_STATUS_FORBIDDEN);
+ soup_server_message_set_status (data->message, SOUP_STATUS_FORBIDDEN, "Forbidden");
else
data->handler->callback (data->server,
data->message,
data->path,
data->query,
- data->client,
data->handler->user_data);
acl_async_handler_free (data);
@@ -1442,10 +1443,9 @@ gupnp_acl_async_callback (GUPnPAcl *acl,
static void
gupnp_acl_server_handler (SoupServer *server,
- SoupMessage *msg,
+ SoupServerMessage *msg,
const char *path,
GHashTable *query,
- SoupClientContext *client,
gpointer user_data)
{
AclServerHandler *handler = (AclServerHandler *) user_data;
@@ -1455,7 +1455,7 @@ gupnp_acl_server_handler (SoupServer *server,
GUPnPContextPrivate *priv;
priv = gupnp_context_get_instance_private (handler->context);
- host = soup_client_context_get_host (client);
+ host = soup_server_message_get_remote_host (msg);
if (handler->service) {
g_object_get (handler->service,
@@ -1467,7 +1467,7 @@ gupnp_acl_server_handler (SoupServer *server,
}
}
- agent = soup_message_headers_get_one (msg->request_headers,
+ agent = soup_message_headers_get_one (soup_server_message_get_request_headers (msg),
"User-Agent");
if (agent == NULL) {
agent = gssdp_client_guess_user_agent
@@ -1483,21 +1483,21 @@ gupnp_acl_server_handler (SoupServer *server,
path,
host,
agent)) {
- soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
+ soup_server_message_set_status (msg, SOUP_STATUS_FORBIDDEN, "Forbidden");
return;
}
} else {
AclAsyncHandler *data;
- data = acl_async_handler_new (server, msg, path, query, client, handler);
+ data = acl_async_handler_new (server, msg, path, query, handler);
soup_server_pause_message (server, msg);
gupnp_acl_is_allowed_async (priv->acl,
device,
handler->service,
path,
- soup_client_context_get_host (client),
+ host,
agent,
NULL,
(GAsyncReadyCallback) gupnp_acl_async_callback,
@@ -1508,7 +1508,7 @@ gupnp_acl_server_handler (SoupServer *server,
}
/* Delegate to orignal callback */
- handler->callback (server, msg, path, query, client, handler->user_data);
+ handler->callback (server, msg, path, query, handler->user_data);
}
/**
@@ -1563,6 +1563,8 @@ _gupnp_context_add_server_handler_with_data (GUPnPContext *context,
g_return_if_fail (GUPNP_IS_CONTEXT (context));
+ g_print ("Adding ACL-Protected handler for %s\n", path);
+
priv = gupnp_context_get_instance_private (context);
soup_server_add_handler (priv->server,
path,
@@ -1607,7 +1609,7 @@ gupnp_context_remove_server_handler (GUPnPContext *context, const char *path)
char *
gupnp_context_rewrite_uri (GUPnPContext *context, const char *uri)
{
- SoupURI *soup_uri = NULL;
+ GUri *soup_uri = NULL;
char *retval = NULL;
soup_uri = gupnp_context_rewrite_uri_to_uri (context, uri);
@@ -1616,8 +1618,8 @@ gupnp_context_rewrite_uri (GUPnPContext *context, const char *uri)
return NULL;
}
- retval = soup_uri_to_string (soup_uri, FALSE);
- soup_uri_free (soup_uri);
+ retval = g_uri_to_string_partial (soup_uri, G_URI_HIDE_PASSWORD);
+ g_uri_unref (soup_uri);
return retval;
}
@@ -1636,23 +1638,26 @@ gupnp_context_rewrite_uri (GUPnPContext *context, const char *uri)
* Since: 1.2.3
* Stability: Private
*/
-SoupURI *
+GUri *
gupnp_context_rewrite_uri_to_uri (GUPnPContext *context, const char *uri)
{
const char *host = NULL;
- SoupURI *soup_uri = NULL;
+ GUri *soup_uri = NULL;
GInetAddress *addr = NULL;
int index = -1;
+ GError *error = NULL;
- soup_uri = soup_uri_new (uri);
+ soup_uri = g_uri_parse (uri, G_URI_FLAGS_NONE, &error);
- if (soup_uri == NULL) {
- g_warning ("Invalid call-back url: %s", uri);
+ if (error != NULL ) {
+ g_warning ("Invalid call-back url: %s (%s)", uri, error->message);
+
+ g_clear_error (&error);
return NULL;
}
- host = soup_uri_get_host (soup_uri);
+ host = g_uri_get_host (soup_uri);
addr = g_inet_address_new_from_string (host);
index = gssdp_client_get_index (GSSDP_CLIENT (context));
@@ -1663,8 +1668,10 @@ gupnp_context_rewrite_uri_to_uri (GUPnPContext *context, const char *uri)
new_host = g_strdup_printf ("%s%%%d",
host,
index);
- soup_uri_set_host (soup_uri, new_host);
+ GUri *new_uri = soup_uri_copy (soup_uri, SOUP_URI_HOST, new_host, NULL);
g_free (new_host);
+ g_uri_unref (soup_uri);
+ soup_uri = new_uri;
}
g_object_unref (addr);
diff --git a/libgupnp/gupnp-control-point.c b/libgupnp/gupnp-control-point.c
index dc04732..50f032a 100644
--- a/libgupnp/gupnp-control-point.c
+++ b/libgupnp/gupnp-control-point.c
@@ -84,6 +84,7 @@ get_description_url_data_free (GetDescriptionURLData *data)
{
gupnp_control_point_remove_pending_get (data->control_point, data);
if (data->message) {
+#if 0
GUPnPContext *context;
SoupSession *session;
@@ -94,6 +95,7 @@ get_description_url_data_free (GetDescriptionURLData *data)
soup_session_cancel_message (session,
data->message,
SOUP_STATUS_CANCELLED);
+#endif
}
if (data->timeout_source) {
@@ -290,7 +292,7 @@ create_and_report_service_proxy (GUPnPControlPoint *control_point,
const char *udn,
const char *service_type,
const char *description_url,
- SoupURI *url_base)
+ GUri *url_base)
{
GUPnPServiceProxy *proxy;
GUPnPResourceFactory *factory;
@@ -329,7 +331,7 @@ create_and_report_device_proxy (GUPnPControlPoint *control_point,
xmlNode *element,
const char *udn,
const char *description_url,
- SoupURI *url_base)
+ GUri *url_base)
{
GUPnPDeviceProxy *proxy;
GUPnPResourceFactory *factory;
@@ -406,7 +408,7 @@ process_service_list (xmlNode *element,
const char *udn,
const char *service_type,
const char *description_url,
- SoupURI *url_base)
+ GUri *url_base)
{
g_object_ref (control_point);
@@ -452,7 +454,7 @@ process_device_list (xmlNode *element,
const char *udn,
const char *service_type,
const char *description_url,
- SoupURI *url_base)
+ GUri *url_base)
{
g_object_ref (control_point);
@@ -531,7 +533,7 @@ description_loaded (GUPnPControlPoint *control_point,
const char *description_url)
{
xmlNode *element;
- SoupURI *url_base;
+ GUri *url_base;
/* Save the URL base, if any */
element = xml_util_get_element ((xmlNode *)
@@ -551,7 +553,7 @@ description_loaded (GUPnPControlPoint *control_point,
"URLBase",
NULL);
if (!url_base)
- url_base = soup_uri_new (description_url);
+ url_base = g_uri_parse (description_url, G_URI_FLAGS_NONE, NULL);
/* Iterate matching devices */
process_device_list (element,
@@ -563,7 +565,7 @@ description_loaded (GUPnPControlPoint *control_point,
url_base);
/* Cleanup */
- soup_uri_free (url_base);
+ g_uri_unref (url_base);
}
@@ -574,15 +576,21 @@ description_url_retry_timeout (gpointer user_data);
* Description URL downloaded.
*/
static void
-got_description_url (SoupSession *session,
- SoupMessage *msg,
+got_description_url (GObject *source,
+ GAsyncResult *res,
GetDescriptionURLData *data)
{
GUPnPXMLDoc *doc;
GUPnPControlPointPrivate *priv;
+ GError *error = NULL;
+ SoupMessage *message = data->message;
- if (msg->status_code == SOUP_STATUS_CANCELLED)
- return;
+ GBytes *body = soup_session_send_and_read_finish (SOUP_SESSION (source), res, &error);
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ goto out;
+
+ // FIXME: What to do on other errors...
data->message = NULL;
priv = gupnp_control_point_get_instance_private (data->control_point);
@@ -600,16 +608,19 @@ got_description_url (SoupSession *session,
get_description_url_data_free (data);
- return;
+ goto out;
}
/* Not cached */
- if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+ if (SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (message))) {
xmlDoc *xml_doc;
+ gsize length;
+ gconstpointer body_data;
+
+ body_data = g_bytes_get_data (body, &length);
/* Parse response */
- xml_doc = xmlRecoverMemory (msg->response_body->data,
- msg->response_body->length);
+ xml_doc = xmlRecoverMemory (body_data, length);
if (xml_doc) {
doc = gupnp_xml_doc_new (xml_doc);
@@ -637,17 +648,15 @@ got_description_url (SoupSession *session,
get_description_url_data_free (data);
} else {
- GMainContext *async_context;
+ GMainContext *async_context = g_main_context_get_thread_default ();
/* Retry GET after a timeout */
- async_context = soup_session_get_async_context (session);
-
data->tries--;
if (data->tries > 0) {
g_warning ("Failed to GET %s: %s, retrying in %d seconds",
data->description_url,
- msg->reason_phrase,
+ soup_message_get_reason_phrase (message),
data->timeout);
data->timeout_source = g_timeout_source_new_seconds
@@ -662,6 +671,10 @@ got_description_url (SoupSession *session,
g_warning ("Maximum number of retries failed, not trying again");
}
}
+
+out:
+ g_bytes_unref (body);
+ g_object_unref (message);
}
/*
@@ -735,11 +748,12 @@ load_description (GUPnPControlPoint *control_point,
priv->pending_gets = g_list_prepend (priv->pending_gets,
data);
- soup_session_queue_message (session,
- data->message,
- (SoupSessionCallback)
- got_description_url,
- data);
+ soup_session_send_and_read_async (session,
+ data->message,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ (GAsyncReadyCallback)got_description_url,
+ data);
}
}
diff --git a/libgupnp/gupnp-device-info.c b/libgupnp/gupnp-device-info.c
index fd3d8ce..7c1b6be 100644
--- a/libgupnp/gupnp-device-info.c
+++ b/libgupnp/gupnp-device-info.c
@@ -31,7 +31,7 @@ struct _GUPnPDeviceInfoPrivate {
char *udn;
char *device_type;
- SoupURI *url_base;
+ GUri *url_base;
GUPnPXMLDoc *doc;
@@ -177,7 +177,7 @@ gupnp_device_info_finalize (GObject *object)
g_free (priv->udn);
g_free (priv->device_type);
- g_clear_pointer (&priv->url_base, soup_uri_free);
+ g_clear_pointer (&priv->url_base, g_uri_unref);
G_OBJECT_CLASS (gupnp_device_info_parent_class)->finalize (object);
}
@@ -296,7 +296,7 @@ gupnp_device_info_class_init (GUPnPDeviceInfoClass *klass)
g_param_spec_boxed ("url-base",
"URL base",
"The URL base",
- SOUP_TYPE_URI,
+ G_TYPE_URI,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_NAME |
@@ -413,7 +413,7 @@ gupnp_device_info_get_location (GUPnPDeviceInfo *info)
*
* Returns: A #SoupURI.
**/
-const SoupURI *
+const GUri *
gupnp_device_info_get_url_base (GUPnPDeviceInfo *info)
{
GUPnPDeviceInfoPrivate *priv;
@@ -910,12 +910,11 @@ gupnp_device_info_get_icon_url (GUPnPDeviceInfo *info,
*height = icon->height;
if (icon->url) {
- SoupURI *uri;
+ GUri *uri;
- uri = soup_uri_new_with_base (priv->url_base,
- (const char *) icon->url);
- ret = soup_uri_to_string (uri, FALSE);
- soup_uri_free (uri);
+ uri = g_uri_parse_relative (priv->url_base, (const char *) icon->url,
G_URI_FLAGS_NONE, NULL);
+ ret = g_uri_to_string_partial (uri, G_URI_HIDE_PASSWORD);
+ g_uri_unref (uri);
} else
ret = NULL;
} else {
diff --git a/libgupnp/gupnp-device-info.h b/libgupnp/gupnp-device-info.h
index 8ee35d7..0a08bdf 100644
--- a/libgupnp/gupnp-device-info.h
+++ b/libgupnp/gupnp-device-info.h
@@ -11,7 +11,6 @@
#include <glib-object.h>
#include <libxml/tree.h>
-#include <libsoup/soup-uri.h>
#include "gupnp-context.h"
#include "gupnp-service-info.h"
@@ -56,7 +55,7 @@ gupnp_device_info_get_context (GUPnPDeviceInfo *info);
const char *
gupnp_device_info_get_location (GUPnPDeviceInfo *info);
-const SoupURI *
+const GUri *
gupnp_device_info_get_url_base (GUPnPDeviceInfo *info);
const char *
diff --git a/libgupnp/gupnp-device-proxy.c b/libgupnp/gupnp-device-proxy.c
index ea0d6ca..ea9ff9c 100644
--- a/libgupnp/gupnp-device-proxy.c
+++ b/libgupnp/gupnp-device-proxy.c
@@ -37,7 +37,7 @@ gupnp_device_proxy_get_device (GUPnPDeviceInfo *info,
GUPnPContext *context;
GUPnPXMLDoc *doc;
const char *location;
- const SoupURI *url_base;
+ const GUri *url_base;
factory = gupnp_device_info_get_resource_factory (info);
context = gupnp_device_info_get_context (info);
@@ -65,7 +65,7 @@ gupnp_device_proxy_get_service (GUPnPDeviceInfo *info,
GUPnPContext *context;
GUPnPXMLDoc *doc;
const char *location, *udn;
- const SoupURI *url_base;
+ const GUri *url_base;
factory = gupnp_device_info_get_resource_factory (info);
context = gupnp_device_info_get_context (info);
diff --git a/libgupnp/gupnp-device.c b/libgupnp/gupnp-device.c
index 71b11cf..ad39345 100644
--- a/libgupnp/gupnp-device.c
+++ b/libgupnp/gupnp-device.c
@@ -50,7 +50,7 @@ gupnp_device_get_device (GUPnPDeviceInfo *info,
GUPnPContext *context;
GUPnPDevice *root_device;
const char *location;
- const SoupURI *url_base;
+ const GUri *url_base;
device = GUPNP_DEVICE (info);
priv = gupnp_device_get_instance_private (device);
@@ -90,7 +90,7 @@ gupnp_device_get_service (GUPnPDeviceInfo *info,
GUPnPContext *context;
GUPnPDevice *root_device;
const char *location, *udn;
- const SoupURI *url_base;
+ const GUri *url_base;
device = GUPNP_DEVICE (info);
priv = gupnp_device_get_instance_private (device);
diff --git a/libgupnp/gupnp-error.c b/libgupnp/gupnp-error.c
index 7dcf5db..079ddd4 100644
--- a/libgupnp/gupnp-error.c
+++ b/libgupnp/gupnp-error.c
@@ -130,8 +130,8 @@ _gupnp_error_set_server_error (GError **error,
{
g_set_error_literal (error,
GUPNP_SERVER_ERROR,
- code_from_status_code (msg->status_code),
- msg->reason_phrase);
+ code_from_status_code (soup_message_get_status (msg)),
+ soup_message_get_reason_phrase (msg));
}
/* Create a #GError with status of @msg */
@@ -139,6 +139,6 @@ GError *
_gupnp_error_new_server_error (SoupMessage *msg)
{
return g_error_new_literal (GUPNP_SERVER_ERROR,
- code_from_status_code (msg->status_code),
- msg->reason_phrase);
+ code_from_status_code (soup_message_get_status (msg)),
+ soup_message_get_reason_phrase (msg));
}
diff --git a/libgupnp/gupnp-resource-factory-private.h b/libgupnp/gupnp-resource-factory-private.h
index 9a5f10d..a850d84 100644
--- a/libgupnp/gupnp-resource-factory-private.h
+++ b/libgupnp/gupnp-resource-factory-private.h
@@ -29,7 +29,7 @@ gupnp_resource_factory_create_device_proxy
xmlNode *element,
const char *udn,
const char *location,
- const SoupURI *url_base);
+ const GUri *url_base);
G_GNUC_INTERNAL GUPnPServiceProxy *
gupnp_resource_factory_create_service_proxy
@@ -40,7 +40,7 @@ gupnp_resource_factory_create_service_proxy
const char *udn,
const char *service_type,
const char *location,
- const SoupURI *url_base);
+ const GUri *url_base);
G_GNUC_INTERNAL GUPnPDevice *
gupnp_resource_factory_create_device (GUPnPResourceFactory *factory,
@@ -49,7 +49,7 @@ gupnp_resource_factory_create_device (GUPnPResourceFactory *factory,
xmlNode *element,
const char *udn,
const char *location,
- const SoupURI *url_base);
+ const GUri *url_base);
G_GNUC_INTERNAL GUPnPService *
gupnp_resource_factory_create_service (GUPnPResourceFactory *factory,
@@ -58,7 +58,7 @@ gupnp_resource_factory_create_service (GUPnPResourceFactory *factory,
xmlNode *element,
const char *udn,
const char *location,
- const SoupURI *url_base);
+ const GUri *url_base);
G_END_DECLS
diff --git a/libgupnp/gupnp-resource-factory.c b/libgupnp/gupnp-resource-factory.c
index 8d7e362..1a23104 100644
--- a/libgupnp/gupnp-resource-factory.c
+++ b/libgupnp/gupnp-resource-factory.c
@@ -199,7 +199,7 @@ gupnp_resource_factory_create_device_proxy
xmlNode *element,
const char *udn,
const char *location,
- const SoupURI *url_base)
+ const GUri *url_base)
{
GUPnPDeviceProxy *proxy;
GType proxy_type;
@@ -259,7 +259,7 @@ gupnp_resource_factory_create_service_proxy
const char *udn,
const char *service_type,
const char *location,
- const SoupURI *url_base)
+ const GUri *url_base)
{
GUPnPServiceProxy *proxy;
GType proxy_type = GUPNP_TYPE_SERVICE_PROXY;
@@ -316,7 +316,7 @@ gupnp_resource_factory_create_device
xmlNode *element,
const char *udn,
const char *location,
- const SoupURI *url_base)
+ const GUri *url_base)
{
GUPnPDevice *device;
GType device_type = GUPNP_TYPE_DEVICE;
@@ -372,7 +372,7 @@ gupnp_resource_factory_create_service
xmlNode *element,
const char *udn,
const char *location,
- const SoupURI *url_base)
+ const GUri *url_base)
{
GUPnPService *service;
GType service_type = GUPNP_TYPE_SERVICE;
diff --git a/libgupnp/gupnp-root-device.c b/libgupnp/gupnp-root-device.c
index 48987c4..fa96012 100644
--- a/libgupnp/gupnp-root-device.c
+++ b/libgupnp/gupnp-root-device.c
@@ -288,10 +288,10 @@ gupnp_root_device_initable_init (GInitable *initable,
GUPnPRootDevice *device;
GUPnPContext *context;
const char *udn;
- SoupURI *uri;
+ GUri *uri;
char *desc_path, *location, *usn, *relative_location;
xmlNode *root_element, *element;
- SoupURI *url_base;
+ GUri *url_base;
gboolean result = FALSE;
GUPnPRootDevicePrivate *priv;
@@ -409,9 +409,9 @@ gupnp_root_device_initable_init (GInitable *initable,
gupnp_context_host_path (context, priv->description_dir, "");
/* Generate full location */
- soup_uri_set_path (uri, relative_location);
- location = soup_uri_to_string (uri, FALSE);
-
+ GUri *new_uri = soup_uri_copy (uri, SOUP_URI_PATH, relative_location, NULL);
+ location = g_uri_to_string_partial (new_uri, G_URI_HIDE_PASSWORD);
+ g_uri_unref (new_uri);
g_free (relative_location);
/* Save the URL base, if any */
@@ -419,15 +419,14 @@ gupnp_root_device_initable_init (GInitable *initable,
"URLBase",
NULL);
if (!url_base)
- url_base = soup_uri_new (location);
+ url_base = g_uri_parse (location, G_URI_FLAGS_NONE, NULL);
/* Set additional properties */
g_object_set (G_OBJECT (device),
"location", location,
"url-base", url_base,
NULL);
-
- soup_uri_free (url_base);
+ g_uri_unref (url_base);
/* Create resource group */
priv->group = gssdp_resource_group_new (GSSDP_CLIENT (context));
@@ -447,7 +446,7 @@ gupnp_root_device_initable_init (GInitable *initable,
DONE:
/* Cleanup */
if (uri)
- soup_uri_free (uri);
+ g_uri_unref (uri);
g_free (desc_path);
g_free (location);
diff --git a/libgupnp/gupnp-service-info.c b/libgupnp/gupnp-service-info.c
index 9a9f4de..1705306 100644
--- a/libgupnp/gupnp-service-info.c
+++ b/libgupnp/gupnp-service-info.c
@@ -38,7 +38,7 @@ struct _GUPnPServiceInfoPrivate {
char *udn;
char *service_type;
- SoupURI *url_base;
+ GUri *url_base;
GUPnPXMLDoc *doc;
@@ -178,9 +178,9 @@ gupnp_service_info_dispose (GObject *object)
/* Cancel any pending SCPD GETs */
if (priv->context) {
- SoupSession *session;
+ //SoupSession *session;
- session = gupnp_context_get_session (priv->context);
+ //session = gupnp_context_get_session (priv->context);
while (priv->pending_gets) {
GetSCPDURLData *data;
@@ -191,9 +191,11 @@ gupnp_service_info_dispose (GObject *object)
g_cancellable_disconnect (data->cancellable,
data->cancelled_id);
+ /*
soup_session_cancel_message (session,
data->message,
SOUP_STATUS_CANCELLED);
+ */
get_scpd_url_data_free (data);
@@ -228,7 +230,7 @@ gupnp_service_info_finalize (GObject *object)
g_free (priv->udn);
g_free (priv->service_type);
- soup_uri_free (priv->url_base);
+ g_uri_unref (priv->url_base);
G_OBJECT_CLASS (gupnp_service_info_parent_class)->finalize (object);
}
@@ -329,7 +331,7 @@ gupnp_service_info_class_init (GUPnPServiceInfoClass *klass)
g_param_spec_boxed ("url-base",
"URL base",
"The URL base",
- SOUP_TYPE_URI,
+ G_TYPE_URI,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_NAME |
@@ -426,7 +428,7 @@ gupnp_service_info_get_location (GUPnPServiceInfo *info)
*
* Returns: A constant #SoupURI.
**/
-const SoupURI *
+const GUri *
gupnp_service_info_get_url_base (GUPnPServiceInfo *info)
{
GUPnPServiceInfoPrivate *priv;
@@ -575,8 +577,8 @@ gupnp_service_info_get_event_subscription_url (GUPnPServiceInfo *info)
* SCPD URL downloaded.
*/
static void
-got_scpd_url (G_GNUC_UNUSED SoupSession *session,
- SoupMessage *msg,
+got_scpd_url (GObject *source,
+ GAsyncResult *res,
GetSCPDURLData *data)
{
GUPnPServiceIntrospection *introspection;
@@ -586,14 +588,20 @@ got_scpd_url (G_GNUC_UNUSED SoupSession *session,
introspection = NULL;
error = NULL;
- if (msg->status_code == SOUP_STATUS_CANCELLED)
+ GBytes *body = soup_session_send_and_read_finish (SOUP_SESSION (source), res, &error);
+
+ SoupStatus status = soup_message_get_status (data->message);
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
- if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+ if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
xmlDoc *scpd;
+ gsize length;
- scpd = xmlRecoverMemory (msg->response_body->data,
- msg->response_body->length);
+ gconstpointer data = g_bytes_get_data (body, &length);
+
+ scpd = xmlRecoverMemory (data, length);
if (scpd) {
introspection = gupnp_service_introspection_new (scpd);
@@ -607,7 +615,7 @@ got_scpd_url (G_GNUC_UNUSED SoupSession *session,
"Could not parse SCPD");
}
} else
- error = _gupnp_error_new_server_error (msg);
+ error = _gupnp_error_new_server_error (data->message);
/* prevent the callback from canceling the cancellable
* (and so freeing data just before we do) */
@@ -635,7 +643,7 @@ cancellable_cancelled_cb (GCancellable *cancellable,
{
GUPnPServiceInfo *info;
GetSCPDURLData *data;
- SoupSession *session;
+ //SoupSession *session;
GError *error;
GUPnPServiceInfoPrivate *priv;
@@ -644,10 +652,13 @@ cancellable_cancelled_cb (GCancellable *cancellable,
priv = gupnp_service_info_get_instance_private (info);
+ /*
+ FIXME: Should have been part of the cancellable
session = gupnp_context_get_session (priv->context);
soup_session_cancel_message (session,
data->message,
SOUP_STATUS_CANCELLED);
+ */
priv->pending_gets = g_list_remove (priv->pending_gets, data);
@@ -780,10 +791,7 @@ gupnp_service_info_get_introspection_async_full
session = gupnp_context_get_session (priv->context);
- soup_session_queue_message (session,
- data->message,
- (SoupSessionCallback) got_scpd_url,
- data);
+ soup_session_send_and_read_async (session, data->message, G_PRIORITY_DEFAULT, cancellable,
(GAsyncReadyCallback)got_scpd_url, data);
data->cancellable = cancellable;
if (data->cancellable) {
diff --git a/libgupnp/gupnp-service-info.h b/libgupnp/gupnp-service-info.h
index a853c2f..dc42964 100644
--- a/libgupnp/gupnp-service-info.h
+++ b/libgupnp/gupnp-service-info.h
@@ -10,7 +10,6 @@
#define GUPNP_SERVICE_INFO_H
#include <glib-object.h>
-#include <libsoup/soup-uri.h>
#include "gupnp-context.h"
#include "gupnp-service-introspection.h"
@@ -57,7 +56,7 @@ gupnp_service_info_get_context (GUPnPServiceInfo *info);
const char *
gupnp_service_info_get_location (GUPnPServiceInfo *info);
-const SoupURI *
+const GUri *
gupnp_service_info_get_url_base (GUPnPServiceInfo *info);
const char *
diff --git a/libgupnp/gupnp-service-private.h b/libgupnp/gupnp-service-private.h
index 1915505..f1f31c8 100644
--- a/libgupnp/gupnp-service-private.h
+++ b/libgupnp/gupnp-service-private.h
@@ -14,7 +14,7 @@ struct _GUPnPServiceAction {
char *name;
- SoupMessage *msg;
+ SoupServerMessage *msg;
gboolean accept_gzip;
GUPnPXMLDoc *doc;
diff --git a/libgupnp/gupnp-service-proxy-action-private.h b/libgupnp/gupnp-service-proxy-action-private.h
index cb6492b..8fc8981 100644
--- a/libgupnp/gupnp-service-proxy-action-private.h
+++ b/libgupnp/gupnp-service-proxy-action-private.h
@@ -137,6 +137,7 @@ struct _GUPnPServiceProxyAction {
gint header_pos;
SoupMessage *msg;
+ GBytes *response;
GString *msg_str;
GCancellable *cancellable;
diff --git a/libgupnp/gupnp-service-proxy-action.c b/libgupnp/gupnp-service-proxy-action.c
index 4d9336c..dedf3b4 100644
--- a/libgupnp/gupnp-service-proxy-action.c
+++ b/libgupnp/gupnp-service-proxy-action.c
@@ -65,7 +65,7 @@ check_action_response (G_GNUC_UNUSED GUPnPServiceProxy *proxy,
xmlDoc *response;
int code;
- if (action->msg == NULL) {
+ if (action->msg == NULL || action->response == NULL) {
g_set_error (error,
GUPNP_SERVER_ERROR,
GUPNP_SERVER_ERROR_INVALID_RESPONSE,
@@ -74,8 +74,10 @@ check_action_response (G_GNUC_UNUSED GUPnPServiceProxy *proxy,
return NULL;
}
+ SoupStatus status = soup_message_get_status (action->msg);
+
/* Check for errors */
- switch (action->msg->status_code) {
+ switch (status) {
case SOUP_STATUS_OK:
case SOUP_STATUS_INTERNAL_SERVER_ERROR:
break;
@@ -86,11 +88,14 @@ check_action_response (G_GNUC_UNUSED GUPnPServiceProxy *proxy,
}
/* Parse response */
- response = xmlRecoverMemory (action->msg->response_body->data,
- action->msg->response_body->length);
+ gconstpointer data;
+ gsize length;
+ data = g_bytes_get_data (action->response, &length);
+ response = xmlRecoverMemory (data, length);
+ g_clear_pointer (&action->response, g_bytes_unref);
if (!response) {
- if (action->msg->status_code == SOUP_STATUS_OK) {
+ if (status == SOUP_STATUS_OK) {
g_set_error (error,
GUPNP_SERVER_ERROR,
GUPNP_SERVER_ERROR_INVALID_RESPONSE,
@@ -100,7 +105,7 @@ check_action_response (G_GNUC_UNUSED GUPnPServiceProxy *proxy,
(error,
GUPNP_SERVER_ERROR,
GUPNP_SERVER_ERROR_INTERNAL_SERVER_ERROR,
- action->msg->reason_phrase);
+ soup_message_get_reason_phrase (action->msg));
}
return NULL;
@@ -137,7 +142,7 @@ check_action_response (G_GNUC_UNUSED GUPnPServiceProxy *proxy,
}
/* Check whether we have a Fault */
- if (action->msg->status_code == SOUP_STATUS_INTERNAL_SERVER_ERROR) {
+ if (status == SOUP_STATUS_INTERNAL_SERVER_ERROR) {
xmlNode *param;
char *desc;
@@ -175,7 +180,7 @@ check_action_response (G_GNUC_UNUSED GUPnPServiceProxy *proxy,
desc = xml_util_get_child_element_content_glib
(param, "errorDescription");
if (desc == NULL)
- desc = g_strdup (action->msg->reason_phrase);
+ desc = g_strdup (soup_message_get_reason_phrase (action->msg));
g_set_error_literal (error,
GUPNP_CONTROL_ERROR,
diff --git a/libgupnp/gupnp-service-proxy.c b/libgupnp/gupnp-service-proxy.c
index 9f4b61e..953c88a 100644
--- a/libgupnp/gupnp-service-proxy.c
+++ b/libgupnp/gupnp-service-proxy.c
@@ -90,9 +90,10 @@ typedef struct {
} EmitNotifyData;
static void
-subscribe_got_response (SoupSession *session,
- SoupMessage *msg,
- GUPnPServiceProxy *proxy);
+subscribe_got_response (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data);
+
static void
subscribe (GUPnPServiceProxy *proxy);
static void
@@ -223,7 +224,7 @@ gupnp_service_proxy_dispose (GObject *object)
GUPnPServiceProxyPrivate *priv;
GObjectClass *object_class;
GUPnPContext *context;
- SoupSession *session;
+ //SoupSession *session;
proxy = GUPNP_SERVICE_PROXY (object);
priv = gupnp_service_proxy_get_instance_private (proxy);
@@ -258,19 +259,24 @@ gupnp_service_proxy_dispose (GObject *object)
}
/* Cancel pending messages */
+#if 0
if (context)
session = gupnp_context_get_session (context);
else
session = NULL; /* Not the first time dispose is called. */
+#endif
while (priv->pending_messages) {
+ /*
SoupMessage *msg;
msg = priv->pending_messages->data;
+ * FIXME: Porbably cancelled above...
soup_session_cancel_message (session,
msg,
SOUP_STATUS_CANCELLED);
+ */
priv->pending_messages =
g_list_delete_link (priv->pending_messages,
@@ -604,17 +610,20 @@ on_action_cancelled (GCancellable *cancellable, gpointer user_data)
{
GUPnPServiceProxyAction *action = (GUPnPServiceProxyAction *) user_data;
- GUPnPContext *context;
- SoupSession *session;
+// GUPnPContext *context;
+// SoupSession *session;
if (action->msg != NULL && action->proxy != NULL) {
+#if 0
context = gupnp_service_info_get_context
(GUPNP_SERVICE_INFO (action->proxy));
session = gupnp_context_get_session (context);
+ FIXME: Cancellable?
soup_session_cancel_message (session,
action->msg,
SOUP_STATUS_CANCELLED);
+#endif
action->cancellable_connection_id = 0;
}
}
@@ -668,9 +677,11 @@ prepare_action_msg (GUPnPServiceProxy *proxy,
action->msg = soup_message_new (SOUP_METHOD_POST, local_control_url);
g_free (local_control_url);
+ SoupMessageHeaders *headers = soup_message_get_request_headers (action->msg);
+
/* Specify action */
full_action = g_strdup_printf ("\"%s#%s\"", service_type, action->name);
- soup_message_headers_append (action->msg->request_headers,
+ soup_message_headers_append (headers,
"SOAPAction",
full_action);
g_free (full_action);
@@ -679,18 +690,14 @@ prepare_action_msg (GUPnPServiceProxy *proxy,
http_request_set_accept_language (action->msg);
/* Accept gzip encoding */
- soup_message_headers_append (action->msg->request_headers,
+ soup_message_headers_append (headers,
"Accept-Encoding", "gzip");
gupnp_service_proxy_action_serialize (action, service_type);
- soup_message_set_request (action->msg,
+ soup_message_set_request_body_from_bytes (action->msg,
"text/xml; charset=\"utf-8\"",
- SOUP_MEMORY_TAKE,
- action->msg_str->str,
- action->msg_str->len);
-
- g_string_free (action->msg_str, FALSE);
+ g_string_free_to_bytes (action->msg_str));
action->msg_str = NULL;
return TRUE;
@@ -702,51 +709,51 @@ update_message_after_not_allowed (SoupMessage *msg)
const char *full_action;
/* Retry with M-POST */
- msg->method = "M-POST";
+ soup_message_set_method (msg, "M-POST");
+
+ SoupMessageHeaders *headers = soup_message_get_request_headers (msg);
- soup_message_headers_append
- (msg->request_headers,
- "Man",
- "\"http://schemas.xmlsoap.org/soap/envelope/\"; ns=s");
+ soup_message_headers_append (headers,
+ "Man",
+ "\"http://schemas.xmlsoap.org/soap/envelope/\"; ns=s");
/* Rename "SOAPAction" to "s-SOAPAction" */
- full_action = soup_message_headers_get_one
- (msg->request_headers,
- "SOAPAction");
- soup_message_headers_append (msg->request_headers,
- "s-SOAPAction",
- full_action);
- soup_message_headers_remove (msg->request_headers,
- "SOAPAction");
+ full_action = soup_message_headers_get_one (headers, "SOAPAction");
+ soup_message_headers_append (headers, "s-SOAPAction", full_action);
+ soup_message_headers_remove (headers, "SOAPAction");
}
static void
-action_task_got_response (SoupSession *session,
- SoupMessage *msg,
+action_task_got_response (GObject *source,
+ GAsyncResult *res,
gpointer user_data)
{
GTask *task = G_TASK (user_data);
+ GError *error = NULL;
GUPnPServiceProxyAction *action = (GUPnPServiceProxyAction *) g_task_get_task_data (task);
- switch (msg->status_code) {
- case SOUP_STATUS_CANCELLED:
+ action->response = soup_session_send_and_read_finish (SOUP_SESSION (source), res, &error);
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
if (action->cancellable != NULL && action->cancellable_connection_id != 0) {
g_cancellable_disconnect (action->cancellable,
action->cancellable_connection_id);
action->cancellable_connection_id = 0;
}
+ }
- g_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_CANCELLED,
- "Action message was cancelled");
+ if (error != NULL) {
+ g_task_return_error (task, error);
g_object_unref (task);
- break;
+ return;
+ }
+
+ switch (soup_message_get_status (action->msg)) {
case SOUP_STATUS_METHOD_NOT_ALLOWED:
/* And re-queue */
- update_message_after_not_allowed (msg);
- soup_session_requeue_message (session, msg);
+ update_message_after_not_allowed (action->msg);
+ //FIXME: soup_session_requeue_message (session, msg);
break;
@@ -783,10 +790,12 @@ gupnp_service_proxy_action_queue_task (GTask *task)
(GUPNP_SERVICE_INFO (action->proxy));
session = gupnp_context_get_session (context);
- soup_session_queue_message (session,
- action->msg,
- (SoupSessionCallback) action_task_got_response,
- task);
+ soup_session_send_and_read_async (session,
+ action->msg,
+ G_PRIORITY_DEFAULT,
+ action->cancellable,
+ (GAsyncReadyCallback) action_task_got_response,
+ task);
action->pending = TRUE;
}
@@ -1494,10 +1503,9 @@ emit_notifications (gpointer user_data)
*/
static void
server_handler (G_GNUC_UNUSED SoupServer *soup_server,
- SoupMessage *msg,
+ SoupServerMessage *msg,
G_GNUC_UNUSED const char *server_path,
G_GNUC_UNUSED GHashTable *query,
- G_GNUC_UNUSED SoupClientContext *soup_client,
gpointer user_data)
{
GUPnPServiceProxy *proxy;
@@ -1510,19 +1518,26 @@ server_handler (G_GNUC_UNUSED SoupServer *soup_server,
EmitNotifyData *emit_notify_data;
proxy = GUPNP_SERVICE_PROXY (user_data);
+ const char *method = soup_server_message_get_method (msg);
- if (strcmp (msg->method, GENA_METHOD_NOTIFY) != 0) {
+ SoupMessageHeaders *request_headers = soup_server_message_get_request_headers (msg);
+
+ if (strcmp (method, GENA_METHOD_NOTIFY) != 0) {
/* We don't implement this method */
- soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_NOT_IMPLEMENTED,
+ "Method not supported");
return;
}
- nt = soup_message_headers_get_one (msg->request_headers, "NT");
- nts = soup_message_headers_get_one (msg->request_headers, "NTS");
+ nt = soup_message_headers_get_one (request_headers, "NT");
+ nts = soup_message_headers_get_one (request_headers, "NTS");
if (nt == NULL || nts == NULL) {
/* Required header is missing */
- soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_BAD_REQUEST,
+ "NT or NTS is missing");
return;
}
@@ -1530,15 +1545,19 @@ server_handler (G_GNUC_UNUSED SoupServer *soup_server,
if (strcmp (nt, "upnp:event") != 0 ||
strcmp (nts, "upnp:propchange") != 0) {
/* Unexpected header content */
- soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_PRECONDITION_FAILED,
+ "Unexpected NT or NTS");
return;
}
- hdr = soup_message_headers_get_one (msg->request_headers, "SEQ");
+ hdr = soup_message_headers_get_one (request_headers, "SEQ");
if (hdr == NULL) {
/* No SEQ header */
- soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_PRECONDITION_FAILED,
+ "SEQ missing");
return;
}
@@ -1547,32 +1566,38 @@ server_handler (G_GNUC_UNUSED SoupServer *soup_server,
seq_parsed = strtoul (hdr, NULL, 10);
if (errno != 0 || seq_parsed > G_MAXUINT32) {
/* Invalid SEQ header value */
- soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_PRECONDITION_FAILED,
+ "SEQ invalid");
return;
}
seq = (guint32) seq_parsed;
- hdr = soup_message_headers_get_one (msg->request_headers, "SID");
+ hdr = soup_message_headers_get_one (request_headers, "SID");
if (hdr == NULL ||
strlen (hdr) <= strlen ("uuid:") ||
strncmp (hdr, "uuid:", strlen ("uuid:")) != 0) {
/* No SID */
- soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_PRECONDITION_FAILED,
+ "SID header missing or malformed");
return;
}
+ SoupMessageBody *request_body = soup_server_message_get_request_body (msg);
+
/* Parse the actual XML message content */
- doc = xmlRecoverMemory (msg->request_body->data,
- msg->request_body->length);
+ doc = xmlRecoverMemory (request_body->data, request_body->length);
if (doc == NULL) {
/* Failed */
g_warning ("Failed to parse NOTIFY message body");
- soup_message_set_status (msg,
- SOUP_STATUS_INTERNAL_SERVER_ERROR);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_INTERNAL_SERVER_ERROR,
+ "Unable to parse NOTIFY message");
return;
}
@@ -1584,7 +1609,7 @@ server_handler (G_GNUC_UNUSED SoupServer *soup_server,
/* Empty or unsupported */
xmlFreeDoc (doc);
- soup_message_set_status (msg, SOUP_STATUS_OK);
+ soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
return;
}
@@ -1610,7 +1635,7 @@ server_handler (G_GNUC_UNUSED SoupServer *soup_server,
}
/* Everything went OK */
- soup_message_set_status (msg, SOUP_STATUS_OK);
+ soup_server_message_set_status (msg, SOUP_STATUS_OK, "Ok");
}
/*
@@ -1629,6 +1654,11 @@ make_timeout_header (GUPnPContext *context)
return g_strdup ("infinite");
}
+typedef struct {
+ GUPnPServiceProxy *proxy;
+ SoupMessage *msg;
+} SubscriptionCallData;
+
/*
* Subscription expired.
*/
@@ -1658,6 +1688,7 @@ subscription_expire (gpointer user_data)
(GUPNP_SERVICE_INFO (proxy));
local_sub_url = gupnp_context_rewrite_uri (context, sub_url);
+
g_free (sub_url);
msg = soup_message_new (GENA_METHOD_SUBSCRIBE, local_sub_url);
@@ -1665,13 +1696,15 @@ subscription_expire (gpointer user_data)
g_return_val_if_fail (msg != NULL, FALSE);
+ SoupMessageHeaders *request_headers = soup_message_get_request_headers (msg);
+
/* Add headers */
- soup_message_headers_append (msg->request_headers,
+ soup_message_headers_append (request_headers,
"SID",
priv->sid);
timeout = make_timeout_header (context);
- soup_message_headers_append (msg->request_headers,
+ soup_message_headers_append (request_headers,
"Timeout",
timeout);
g_free (timeout);
@@ -1682,11 +1715,16 @@ subscription_expire (gpointer user_data)
session = gupnp_context_get_session (context);
- soup_session_queue_message (session,
- msg,
- (SoupSessionCallback)
- subscribe_got_response,
- proxy);
+ SubscriptionCallData *data = g_new0 (SubscriptionCallData, 1);
+ data->msg = msg;
+ data->proxy = proxy;
+
+ soup_session_send_and_read_async (session,
+ msg,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ (GAsyncReadyCallback) subscribe_got_response,
+ data);
return FALSE;
}
@@ -1695,43 +1733,54 @@ subscription_expire (gpointer user_data)
* Received subscription response.
*/
static void
-subscribe_got_response (G_GNUC_UNUSED SoupSession *session,
- SoupMessage *msg,
- GUPnPServiceProxy *proxy)
+subscribe_got_response (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
{
- GError *error;
+ GError *error = NULL;
GUPnPServiceProxyPrivate *priv;
+ SubscriptionCallData *data = user_data;
+
+ GBytes *body = soup_session_send_and_read_finish (SOUP_SESSION (source), res, &error);
+
+ // We don't need the body, it should be empty anyway
+ g_clear_pointer (&body, g_bytes_unref);
/* Cancelled? */
- if (msg->status_code == SOUP_STATUS_CANCELLED)
- return;
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ goto out;
+ } else if (error != NULL) {
+ // FIXME: Is just propagating the error the right way?
+ goto hdr_err;
+ }
/* Remove from pending messages list */
- priv = gupnp_service_proxy_get_instance_private (proxy);
- priv->pending_messages = g_list_remove (priv->pending_messages, msg);
+ priv = gupnp_service_proxy_get_instance_private (data->proxy);
+ priv->pending_messages = g_list_remove (priv->pending_messages, data->msg);
/* Remove subscription timeout */
- if (priv->subscription_timeout_src) {
- g_source_destroy (priv->subscription_timeout_src);
- priv->subscription_timeout_src = NULL;
- }
+ g_clear_pointer (&priv->subscription_timeout_src, g_source_destroy);
/* Check whether the subscription is still wanted */
- if (!priv->subscribed)
- return;
+ if (!priv->subscribed) {
+ goto out;
+ }
/* Reset SID */
g_free (priv->sid);
priv->sid = NULL;
+ SoupStatus status = soup_message_get_status (data->msg);
+ SoupMessageHeaders *response_headers = soup_message_get_response_headers (data->msg);
+
/* Check message status */
- if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+ if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
/* Success. */
const char *hdr;
int timeout;
/* Save SID. */
- hdr = soup_message_headers_get_one (msg->response_headers,
+ hdr = soup_message_headers_get_one (response_headers,
"SID");
if (hdr == NULL) {
error = g_error_new
@@ -1745,12 +1794,12 @@ subscribe_got_response (G_GNUC_UNUSED SoupSession *session,
priv->sid = g_strdup (hdr);
/* Figure out when the subscription times out */
- hdr = soup_message_headers_get_one (msg->response_headers,
+ hdr = soup_message_headers_get_one (response_headers,
"Timeout");
if (hdr == NULL) {
g_warning ("No Timeout in SUBSCRIBE response.");
- return;
+ goto out;
}
if (strncmp (hdr, "Second-", strlen ("Second-")) == 0) {
@@ -1775,7 +1824,7 @@ subscribe_got_response (G_GNUC_UNUSED SoupSession *session,
g_source_set_callback
(priv->subscription_timeout_src,
subscription_expire,
- proxy, NULL);
+ data->proxy, NULL);
g_source_attach (priv->subscription_timeout_src,
g_main_context_get_thread_default ());
@@ -1789,28 +1838,32 @@ subscribe_got_response (G_GNUC_UNUSED SoupSession *session,
error = g_error_new_literal
(GUPNP_EVENTING_ERROR,
GUPNP_EVENTING_ERROR_SUBSCRIPTION_FAILED,
- msg->reason_phrase);
+ soup_message_get_reason_phrase (data->msg));
hdr_err:
/* Remove listener */
context = gupnp_service_info_get_context
- (GUPNP_SERVICE_INFO (proxy));
+ (GUPNP_SERVICE_INFO (data->proxy));
server = gupnp_context_get_server (context);
soup_server_remove_handler (server, priv->path);
priv->subscribed = FALSE;
- g_object_notify (G_OBJECT (proxy), "subscribed");
+ g_object_notify (G_OBJECT (data->proxy), "subscribed");
/* Emit subscription-lost */
- g_signal_emit (proxy,
+ g_signal_emit (data->proxy,
signals[SUBSCRIPTION_LOST],
0,
error);
g_error_free (error);
}
+
+out:
+ g_object_unref (data->msg);
+ g_free (user_data);
}
/*
@@ -1824,7 +1877,7 @@ subscribe (GUPnPServiceProxy *proxy)
SoupMessage *msg;
SoupSession *session;
SoupServer *server;
- SoupURI *uri;
+ GUri *uri;
char *uri_string;
char *sub_url, *delivery_url, *timeout;
@@ -1846,6 +1899,7 @@ subscribe (GUPnPServiceProxy *proxy)
char *local_sub_url = NULL;
local_sub_url = gupnp_context_rewrite_uri (context, sub_url);
+ g_print ("local_sub_uri: %s\n", local_sub_url);
g_free (sub_url);
msg = soup_message_new (GENA_METHOD_SUBSCRIBE, local_sub_url);
@@ -1877,23 +1931,28 @@ subscribe (GUPnPServiceProxy *proxy)
/* Add headers */
uri = _gupnp_context_get_server_uri (context);
- soup_uri_set_path (uri, priv->path);
- uri_string = soup_uri_to_string (uri, FALSE);
- soup_uri_free (uri);
+ GUri *new_uri = soup_uri_copy (uri, SOUP_URI_PATH, priv->path, NULL);
+
+ uri_string = g_uri_to_string_partial (new_uri, G_URI_HIDE_PASSWORD);
+ g_uri_unref (new_uri);
+ g_uri_unref (uri);
+
delivery_url = g_strdup_printf ("<%s>", uri_string);
g_free (uri_string);
- soup_message_headers_append (msg->request_headers,
+ SoupMessageHeaders *request_headers = soup_message_get_request_headers (msg);
+
+ soup_message_headers_append (request_headers,
"Callback",
delivery_url);
g_free (delivery_url);
- soup_message_headers_append (msg->request_headers,
+ soup_message_headers_append (request_headers,
"NT",
"upnp:event");
timeout = make_timeout_header (context);
- soup_message_headers_append (msg->request_headers,
+ soup_message_headers_append (request_headers,
"Timeout",
timeout);
g_free (timeout);
@@ -1913,13 +1972,26 @@ subscribe (GUPnPServiceProxy *proxy)
session = gupnp_context_get_session (context);
- soup_session_queue_message (session,
- msg,
- (SoupSessionCallback)
- subscribe_got_response,
- proxy);
+ SubscriptionCallData *data = g_new0 (SubscriptionCallData, 1);
+
+ data->msg = msg;
+ data->proxy = proxy;
+
+ soup_session_send_and_read_async (session,
+ msg,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ subscribe_got_response,
+ data);
}
+
+static void
+soup_message_dont_care_for_result (GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ GInputStream *s = soup_session_send_finish (SOUP_SESSION (source), res, NULL);
+ g_clear_object (&s);
+}
/*
* Unsubscribe from this service.
*/
@@ -1954,14 +2026,19 @@ unsubscribe (GUPnPServiceProxy *proxy)
if (msg != NULL) {
/* Add headers */
- soup_message_headers_append (msg->request_headers,
+ soup_message_headers_append (soup_message_get_request_headers (msg),
"SID",
priv->sid);
/* And queue it */
session = gupnp_context_get_session (context);
- soup_session_queue_message (session, msg, NULL, NULL);
+ soup_session_send_async (session,
+ msg,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ soup_message_dont_care_for_result,
+ NULL);
}
/* Reset SID */
@@ -2166,28 +2243,31 @@ gupnp_service_proxy_call_action (GUPnPServiceProxy *proxy,
context = gupnp_service_info_get_context (GUPNP_SERVICE_INFO (proxy));
session = gupnp_context_get_session (context);
- soup_session_send_message (session, action->msg);
+ action->response = soup_session_send_and_read (session,
+ action->msg,
+ action->cancellable,
+ error);
- g_cancellable_disconnect (action->cancellable,
- action->cancellable_connection_id);
- action->cancellable_connection_id = 0;
- g_clear_object (&action->cancellable);
+ if (error != NULL && *error != NULL)
+ return NULL;
/* If not allowed, try again */
- if (action->msg->status_code == SOUP_STATUS_METHOD_NOT_ALLOWED) {
+ if (soup_message_get_status (action->msg) == SOUP_STATUS_METHOD_NOT_ALLOWED) {
update_message_after_not_allowed (action->msg);
- soup_session_send_message (session, action->msg);
+ action->response = soup_session_send_and_read (session,
+ action->msg,
+ action->cancellable,
+ error);
+
}
- if (action->msg->status_code == SOUP_STATUS_CANCELLED) {
- g_propagate_error (
- error,
- g_error_new (G_IO_ERROR,
- G_IO_ERROR_CANCELLED,
- "Action message was cancelled"));
+ g_cancellable_disconnect (action->cancellable,
+ action->cancellable_connection_id);
+ action->cancellable_connection_id = 0;
+ g_clear_object (&action->cancellable);
+ if (error != NULL && *error != NULL)
return NULL;
- }
return action;
}
diff --git a/libgupnp/gupnp-service.c b/libgupnp/gupnp-service.c
index 2a33ea5..6ee80c7 100644
--- a/libgupnp/gupnp-service.c
+++ b/libgupnp/gupnp-service.c
@@ -19,7 +19,6 @@
#include <gobject/gvaluecollector.h>
#include <gmodule.h>
-#include <libsoup/soup-date.h>
#include <string.h>
#include "gupnp-service.h"
@@ -78,7 +77,7 @@ enum {
static guint signals[LAST_SIGNAL];
-static char *
+static GBytes *
create_property_set (GQueue *queue);
static void
@@ -143,12 +142,12 @@ gupnp_service_get_session (GUPnPService *service)
* order. The session from GUPnPContext may use
* multiple connections.
*/
- priv->session = soup_session_new_with_options (SOUP_SESSION_MAX_CONNS_PER_HOST, 1,
+ priv->session = soup_session_new_with_options ("max-conns-per-host", 1,
NULL);
if (g_getenv ("GUPNP_DEBUG")) {
SoupLogger *logger;
- logger = soup_logger_new (SOUP_LOGGER_LOG_BODY, -1);
+ logger = soup_logger_new (SOUP_LOGGER_LOG_BODY);
soup_session_add_feature (priv->session,
SOUP_SESSION_FEATURE (logger));
}
@@ -160,19 +159,22 @@ gupnp_service_get_session (GUPnPService *service)
static void
subscription_data_free (SubscriptionData *data)
{
- SoupSession *session;
+ //SoupSession *session;
- session = gupnp_service_get_session (data->service);
+ //session = gupnp_service_get_session (data->service);
/* Cancel pending messages */
while (data->pending_messages) {
+ /*
SoupMessage *msg;
msg = data->pending_messages->data;
+ * FIXME: cancel elsewhere
soup_session_cancel_message (session,
msg,
SOUP_STATUS_CANCELLED);
+ */
data->pending_messages =
g_list_delete_link (data->pending_messages,
@@ -180,7 +182,7 @@ subscription_data_free (SubscriptionData *data)
}
/* Further cleanup */
- g_list_free_full (data->callbacks, (GDestroyNotify) soup_uri_free);
+ g_list_free_full (data->callbacks, (GDestroyNotify) g_uri_unref);
g_free (data->sid);
@@ -270,7 +272,7 @@ finalize_action (GUPnPServiceAction *action)
"\"http://schemas.xmlsoap.org/soap/encoding/\">"
"<s:Body>");
- if (action->msg->status_code != SOUP_STATUS_INTERNAL_SERVER_ERROR) {
+ if (soup_server_message_get_status (action->msg) != SOUP_STATUS_INTERNAL_SERVER_ERROR) {
g_string_append (action->response_str, "</u:");
g_string_append (action->response_str, action->name);
g_string_append (action->response_str, "Response>");
@@ -280,31 +282,33 @@ finalize_action (GUPnPServiceAction *action)
"</s:Body>"
"</s:Envelope>");
- soup_message_headers_replace (action->msg->response_headers,
+ SoupMessageHeaders *headers = soup_server_message_get_response_headers (action->msg);
+
+ soup_message_headers_replace (headers,
"Content-Type",
"text/xml; charset=\"utf-8\"");
if (action->accept_gzip && action->response_str->len > 1024) {
+ // Fixme: Probably easier to use an output stream converter instead
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);
+ SoupMessageBody *msg_body = soup_server_message_get_response_body (action->msg);
+ soup_message_body_append_bytes (msg_body,
+ g_string_free_to_bytes (action->response_str));
}
+ action->response_str = NULL;
- soup_message_headers_append (action->msg->response_headers, "Ext", "");
+ soup_message_headers_append (headers,
+ "Ext", "");
/* Server header on response */
- soup_message_headers_append
- (action->msg->response_headers,
- "Server",
- gssdp_client_get_server_id
- (GSSDP_CLIENT (action->context)));
+ soup_message_headers_append (headers,
+ "Server",
+ gssdp_client_get_server_id
+ (GSSDP_CLIENT (action->context)));
/* Tell soup server that response is now ready */
server = gupnp_context_get_server (action->context);
@@ -345,7 +349,7 @@ gupnp_service_action_get_locales (GUPnPServiceAction *action)
{
g_return_val_if_fail (action != NULL, NULL);
- return http_request_get_accept_locales (action->msg);
+ return http_request_get_accept_locales (soup_server_message_get_request_headers (action->msg));
}
/**
@@ -629,7 +633,7 @@ gupnp_service_action_set_values (GUPnPServiceAction *action,
g_return_if_fail (g_list_length (arg_names) ==
g_list_length (arg_values));
- if (action->msg->status_code == SOUP_STATUS_INTERNAL_SERVER_ERROR) {
+ if (soup_server_message_get_status (action->msg) == SOUP_STATUS_INTERNAL_SERVER_ERROR) {
g_warning ("Calling gupnp_service_action_set_value() after "
"having called gupnp_service_action_return_error() "
"is not allowed.");
@@ -671,7 +675,7 @@ gupnp_service_action_set_value (GUPnPServiceAction *action,
g_return_if_fail (argument != NULL);
g_return_if_fail (value != NULL);
- if (action->msg->status_code == SOUP_STATUS_INTERNAL_SERVER_ERROR) {
+ if (soup_server_message_get_status (action->msg)== SOUP_STATUS_INTERNAL_SERVER_ERROR) {
g_warning ("Calling gupnp_service_action_set_value() after "
"having called gupnp_service_action_return_error() "
"is not allowed.");
@@ -696,7 +700,7 @@ gupnp_service_action_return (GUPnPServiceAction *action)
{
g_return_if_fail (action != NULL);
- soup_message_set_status (action->msg, SOUP_STATUS_OK);
+ soup_server_message_set_status (action->msg, SOUP_STATUS_OK, "Ok");
finalize_action (action);
}
@@ -778,8 +782,9 @@ gupnp_service_action_return_error (GUPnPServiceAction *action,
xml_util_end_element (action->response_str, "s:Fault");
- soup_message_set_status (action->msg,
- SOUP_STATUS_INTERNAL_SERVER_ERROR);
+ soup_server_message_set_status (action->msg,
+ SOUP_STATUS_INTERNAL_SERVER_ERROR,
+ "Internal server error");
finalize_action (action);
}
@@ -791,12 +796,12 @@ gupnp_service_action_return_error (GUPnPServiceAction *action,
* Get the #SoupMessage associated with @action. Mainly intended for
* applications to be able to read HTTP headers received from clients.
*
- * Return value: (transfer full): #SoupMessage associated with @action. Unref
+ * Return value: (transfer full): #SoupServerMessage associated with @action. Unref
* after using it.
*
* Since: 0.14.0
**/
-SoupMessage *
+SoupServerMessage *
gupnp_service_action_get_message (GUPnPServiceAction *action)
{
return g_object_ref (action->msg);
@@ -904,10 +909,9 @@ query_state_variable (GUPnPService *service,
/* controlURL handler */
static void
control_server_handler (SoupServer *server,
- SoupMessage *msg,
+ SoupServerMessage *msg,
G_GNUC_UNUSED const char *server_path,
G_GNUC_UNUSED GHashTable *query,
- G_GNUC_UNUSED SoupClientContext *soup_client,
gpointer user_data)
{
GUPnPService *service;
@@ -922,22 +926,26 @@ control_server_handler (SoupServer *server,
service = GUPNP_SERVICE (user_data);
- if (msg->method != SOUP_METHOD_POST) {
- soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
+ if (soup_server_message_get_method (msg) != SOUP_METHOD_POST) {
+ soup_server_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED, "Not implemented");
return;
}
- if (msg->request_body->length == 0) {
- soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
+ SoupMessageBody *request_body = soup_server_message_get_request_body (msg);
+ SoupMessageHeaders *request_headers = soup_server_message_get_request_headers (msg);
+ SoupMessageHeaders *response_headers = soup_server_message_get_response_headers (msg);
+
+ if (request_body->length == 0) {
+ soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, "Bad request");
return;
}
/* DLNA 7.2.5.6: Always use HTTP 1.1 */
- if (soup_message_get_http_version (msg) == SOUP_HTTP_1_0) {
- soup_message_set_http_version (msg, SOUP_HTTP_1_1);
- soup_message_headers_append (msg->response_headers,
+ if (soup_server_message_get_http_version (msg) == SOUP_HTTP_1_0) {
+ soup_server_message_set_http_version (msg, SOUP_HTTP_1_1);
+ soup_message_headers_append (response_headers,
"Connection",
"close");
}
@@ -945,7 +953,7 @@ control_server_handler (SoupServer *server,
context = gupnp_service_info_get_context (GUPNP_SERVICE_INFO (service));
const char *host_header =
- soup_message_headers_get_one (msg->request_headers, "Host");
+ soup_message_headers_get_one (request_headers, "Host");
if (!gupnp_context_validate_host_header (context, host_header)) {
g_warning ("Host header mismatch, expected %s:%d, got %s",
@@ -953,21 +961,29 @@ control_server_handler (SoupServer *server,
gupnp_context_get_port (context),
host_header);
- soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_PRECONDITION_FAILED,
+ "Host header mismatch");
+
return;
}
/* Get action name */
- soap_action = soup_message_headers_get_one (msg->request_headers,
+ soap_action = soup_message_headers_get_one (request_headers,
"SOAPAction");
if (!soap_action) {
- soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_PRECONDITION_FAILED,
+ "No SOAPAction header");
+
return;
}
action_name = strchr (soap_action, '#');
if (!action_name) {
- soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_PRECONDITION_FAILED,
+ "No action name");
return;
}
@@ -985,10 +1001,12 @@ control_server_handler (SoupServer *server,
*end = '\0';
/* Parse action_node */
- doc = xmlRecoverMemory (msg->request_body->data,
- msg->request_body->length);
+ doc = xmlRecoverMemory (request_body->data,
+ request_body->length);
if (doc == NULL) {
- soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_BAD_REQUEST,
+ "Unable to parse action");
return;
}
@@ -999,7 +1017,9 @@ control_server_handler (SoupServer *server,
action_name,
NULL);
if (!action_node) {
- soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_PRECONDITION_FAILED,
+ "Missing <action>");
return;
}
@@ -1020,7 +1040,7 @@ control_server_handler (SoupServer *server,
action->argument_count++;
/* Get accepted encodings */
- accept_encoding = soup_message_headers_get_list (msg->request_headers,
+ accept_encoding = soup_message_headers_get_list (request_headers,
"Accept-Encoding");
if (accept_encoding) {
@@ -1069,7 +1089,7 @@ control_server_handler (SoupServer *server,
/* Generates a standard (re)subscription response */
static void
subscription_response (GUPnPService *service,
- SoupMessage *msg,
+ SoupServerMessage *msg,
const char *sid,
int timeout)
{
@@ -1080,13 +1100,15 @@ subscription_response (GUPnPService *service,
context = gupnp_service_info_get_context (GUPNP_SERVICE_INFO (service));
client = GSSDP_CLIENT (context);
+ SoupMessageHeaders *response_headers = soup_server_message_get_response_headers (msg);
+
/* Server header on response */
- soup_message_headers_append (msg->response_headers,
+ soup_message_headers_append (response_headers,
"Server",
gssdp_client_get_server_id (client));
/* SID header */
- soup_message_headers_append (msg->response_headers,
+ soup_message_headers_append (response_headers,
"SID",
sid);
@@ -1096,13 +1118,13 @@ subscription_response (GUPnPService *service,
else
tmp = g_strdup ("infinite");
- soup_message_headers_append (msg->response_headers,
+ soup_message_headers_append (response_headers,
"Timeout",
tmp);
g_free (tmp);
/* 200 OK */
- soup_message_set_status (msg, SOUP_STATUS_OK);
+ soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
}
/**
@@ -1150,7 +1172,6 @@ static void
send_initial_state (SubscriptionData *data)
{
GQueue *queue;
- char *mem;
GList *l;
GUPnPServicePrivate *priv;
@@ -1181,13 +1202,13 @@ send_initial_state (SubscriptionData *data)
g_queue_push_tail (queue, ndata);
}
- mem = create_property_set (queue);
- notify_subscriber (data->sid, data, mem);
+ GBytes *property_set = create_property_set (queue);
+ notify_subscriber (data->sid, data, property_set);
/* Cleanup */
g_queue_free (queue);
- g_free (mem);
+ g_bytes_unref (property_set);
}
static GList *
@@ -1195,14 +1216,14 @@ add_subscription_callback (GUPnPContext *context,
GList *list,
const char *callback)
{
- SoupURI *local_uri = NULL;
+ GUri *local_uri = NULL;
local_uri = gupnp_context_rewrite_uri_to_uri (context, callback);
if (local_uri == NULL) {
return list;
}
- const char *host = soup_uri_get_host (local_uri);
+ const char *host = g_uri_get_host (local_uri);
GSocketAddress *address = g_inet_socket_address_new_from_string (host, 0);
// CVE-2020-12695: Ignore subscription call-backs that are not "in
@@ -1219,7 +1240,7 @@ add_subscription_callback (GUPnPContext *context,
/* Subscription request */
static void
subscribe (GUPnPService *service,
- SoupMessage *msg,
+ SoupServerMessage *msg,
const char *callback)
{
SubscriptionData *data;
@@ -1269,7 +1290,9 @@ subscribe (GUPnPService *service,
}
if (!data->callbacks) {
- soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_PRECONDITION_FAILED,
+ "No valid callbacks found");
g_slice_free (SubscriptionData, data);
@@ -1306,7 +1329,7 @@ subscribe (GUPnPService *service,
/* Resubscription request */
static void
resubscribe (GUPnPService *service,
- SoupMessage *msg,
+ SoupServerMessage *msg,
const char *sid)
{
SubscriptionData *data;
@@ -1316,7 +1339,9 @@ resubscribe (GUPnPService *service,
data = g_hash_table_lookup (priv->subscriptions, sid);
if (!data) {
- soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_PRECONDITION_FAILED,
+ "No previous subscription found");
return;
}
@@ -1345,7 +1370,7 @@ resubscribe (GUPnPService *service,
/* Unsubscription request */
static void
unsubscribe (GUPnPService *service,
- SoupMessage *msg,
+ SoupServerMessage *msg,
const char *sid)
{
SubscriptionData *data;
@@ -1360,18 +1385,19 @@ unsubscribe (GUPnPService *service,
sid);
else
data->to_delete = TRUE;
- soup_message_set_status (msg, SOUP_STATUS_OK);
+ soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
} else
- soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED);
+ soup_server_message_set_status (msg,
+ SOUP_STATUS_PRECONDITION_FAILED,
+ "No previous subscription found");
}
/* eventSubscriptionURL handler */
static void
subscription_server_handler (G_GNUC_UNUSED SoupServer *server,
- SoupMessage *msg,
+ SoupServerMessage *msg,
G_GNUC_UNUSED const char *server_path,
G_GNUC_UNUSED GHashTable *query,
- G_GNUC_UNUSED SoupClientContext *soup_client,
gpointer user_data)
{
GUPnPService *service;
@@ -1379,8 +1405,12 @@ subscription_server_handler (G_GNUC_UNUSED SoupServer *server,
service = GUPNP_SERVICE (user_data);
+ SoupMessageHeaders *request_headers = soup_server_message_get_request_headers (msg);
+
+ g_print ("Got SUBSCRIBE handler request\n");
+
const char *host =
- soup_message_headers_get_one (msg->request_headers, "Host");
+ soup_message_headers_get_one (request_headers, "Host");
GUPnPContext *context = gupnp_service_info_get_context (user_data);
if (!gupnp_context_validate_host_header(context, host)) {
g_warning ("Host header mismatch, expected %s:%d, got %s",
@@ -1388,26 +1418,31 @@ subscription_server_handler (G_GNUC_UNUSED SoupServer *server,
gupnp_context_get_port (context),
host);
- soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
+ soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, NULL);
return;
}
- callback = soup_message_headers_get_one (msg->request_headers,
+ callback = soup_message_headers_get_one (request_headers,
"Callback");
- nt = soup_message_headers_get_one (msg->request_headers, "NT");
- sid = soup_message_headers_get_one (msg->request_headers, "SID");
+ nt = soup_message_headers_get_one (request_headers, "NT");
+ sid = soup_message_headers_get_one (request_headers, "SID");
+ const char *method = soup_server_message_get_method (msg);
/* Choose appropriate handler */
- if (strcmp (msg->method, GENA_METHOD_SUBSCRIBE) == 0) {
+ if (strcmp (method, GENA_METHOD_SUBSCRIBE) == 0) {
if (callback) {
if (sid) {
- soup_message_set_status
- (msg, SOUP_STATUS_BAD_REQUEST);
+ soup_server_message_set_status
+ (msg,
+ SOUP_STATUS_BAD_REQUEST,
+ "SID must not be given on SUBSCRIBE");
} else if (!nt || strcmp (nt, "upnp:event") != 0) {
- soup_message_set_status
- (msg, SOUP_STATUS_PRECONDITION_FAILED);
+ soup_server_message_set_status
+ (msg,
+ SOUP_STATUS_PRECONDITION_FAILED,
+ "NT header missing or malformed");
} else {
subscribe (service, msg, callback);
@@ -1416,8 +1451,10 @@ subscription_server_handler (G_GNUC_UNUSED SoupServer *server,
} else if (sid) {
if (nt) {
- soup_message_set_status
- (msg, SOUP_STATUS_BAD_REQUEST);
+ soup_server_message_set_status
+ (msg,
+ SOUP_STATUS_BAD_REQUEST,
+ "NT must not be given on RESUBSCRIBE");
} else {
resubscribe (service, msg, sid);
@@ -1425,16 +1462,16 @@ subscription_server_handler (G_GNUC_UNUSED SoupServer *server,
}
} else {
- soup_message_set_status
- (msg, SOUP_STATUS_PRECONDITION_FAILED);
+ soup_server_message_set_status
+ (msg, SOUP_STATUS_PRECONDITION_FAILED, NULL);
}
- } else if (strcmp (msg->method, GENA_METHOD_UNSUBSCRIBE) == 0) {
+ } else if (strcmp (method, GENA_METHOD_UNSUBSCRIBE) == 0) {
if (sid) {
if (nt || callback) {
- soup_message_set_status
- (msg, SOUP_STATUS_BAD_REQUEST);
+ soup_server_message_set_status
+ (msg, SOUP_STATUS_BAD_REQUEST, NULL);
} else {
unsubscribe (service, msg, sid);
@@ -1442,13 +1479,13 @@ subscription_server_handler (G_GNUC_UNUSED SoupServer *server,
}
} else {
- soup_message_set_status
- (msg, SOUP_STATUS_PRECONDITION_FAILED);
+ soup_server_message_set_status
+ (msg, SOUP_STATUS_PRECONDITION_FAILED, NULL);
}
} else {
- soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
+ soup_server_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED, NULL);
}
}
@@ -1523,12 +1560,19 @@ got_introspection (GUPnPServiceInfo *info,
static char *
path_from_url (const char *url)
{
- SoupURI *uri;
gchar *path;
+ const char *query = NULL;
- uri = soup_uri_new (url);
- path = soup_uri_to_string (uri, TRUE);
- soup_uri_free (uri);
+ GUri *uri = g_uri_parse (url, G_URI_FLAGS_NONE, NULL);
+
+ query = g_uri_get_query (uri);
+ if (query == NULL) {
+ path = g_strdup (g_uri_get_path (uri));
+ } else {
+ path = g_strdup_printf ("%s?%s",
+ g_uri_get_path (uri), query);
+ }
+ g_uri_unref (uri);
return path;
}
@@ -1920,142 +1964,161 @@ gupnp_service_notify_valist (GUPnPService *service,
}
}
+typedef struct {
+ SubscriptionData *data;
+ SoupMessage *msg;
+ GBytes *property_set;
+} NotifySubscriberData;
+
/* Received notify response. */
static void
-notify_got_response (G_GNUC_UNUSED SoupSession *session,
- SoupMessage *msg,
+notify_got_response (GObject *source,
+ GAsyncResult *res,
gpointer user_data)
{
- SubscriptionData *data;
+
+ GBytes *body;
+ GError *error = NULL;
+
+ body = soup_session_send_and_read_finish (SOUP_SESSION (source),
+ res,
+ &error);
/* Cancelled? */
- if (msg->status_code == SOUP_STATUS_CANCELLED)
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_clear_error (&error);
+
return;
+ }
+
+ // We don't need the body
+ g_clear_pointer (&body, g_bytes_unref);
+
+ NotifySubscriberData *data = user_data;
+
+ SoupStatus status = soup_message_get_status (data->msg);
- data = user_data;
/* Remove from pending messages list */
- data->pending_messages = g_list_remove (data->pending_messages, msg);
+ data->data->pending_messages = g_list_remove (data->data->pending_messages, data->msg);
- if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
- data->initial_state_sent = TRUE;
+ if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
+ data->data->initial_state_sent = TRUE;
/* Success: reset callbacks pointer */
- data->callbacks = g_list_first (data->callbacks);
+ data->data->callbacks = g_list_first (data->data->callbacks);
- } else if (msg->status_code == SOUP_STATUS_PRECONDITION_FAILED) {
+ } else if (status == SOUP_STATUS_PRECONDITION_FAILED) {
/* Precondition failed: Cancel subscription */
- gupnp_service_remove_subscription (data->service, data->sid);
+ gupnp_service_remove_subscription (data->data->service, data->data->sid);
} else {
/* Other failure: Try next callback or signal failure. */
- if (data->callbacks->next) {
- SoupBuffer *buffer;
- guint8 *property_set;
- gsize length;
-
+ if (data->data->callbacks->next) {
/* Call next callback */
- data->callbacks = data->callbacks->next;
-
- /* Get property-set from old message */
- buffer = soup_message_body_flatten (msg->request_body);
- soup_buffer_get_data (buffer,
- (const guint8 **) &property_set,
- &length);
- notify_subscriber (NULL, data, property_set);
- soup_buffer_free (buffer);
+ data->data->callbacks = data->data->callbacks->next;
+
+ notify_subscriber (NULL, data->data, g_bytes_ref (data->property_set));
+ g_bytes_unref (data->property_set);
} else {
/* Emit 'notify-failed' signal */
- GError *error;
+ GError *inner_error;
- error = g_error_new_literal
+ inner_error = g_error_new_literal
(GUPNP_EVENTING_ERROR,
GUPNP_EVENTING_ERROR_NOTIFY_FAILED,
- msg->reason_phrase);
+ soup_message_get_reason_phrase (data->msg));
- g_signal_emit (data->service,
+ g_signal_emit (data->data->service,
signals[NOTIFY_FAILED],
0,
- data->callbacks,
- error);
+ data->data->callbacks,
+ inner_error);
- g_error_free (error);
+ g_error_free (inner_error);
/* Reset callbacks pointer */
- data->callbacks = g_list_first (data->callbacks);
+ data->data->callbacks = g_list_first (data->data->callbacks);
}
}
+
+ g_clear_error (&error);
+ g_bytes_unref (data->property_set);
+ g_object_unref (data->msg);
+ g_free (data);
}
+
/* Send notification @user_data to subscriber @value */
static void
notify_subscriber (G_GNUC_UNUSED gpointer key,
gpointer value,
gpointer user_data)
{
- SubscriptionData *data;
- const char *property_set;
char *tmp;
- SoupMessage *msg;
SoupSession *session;
- data = value;
- property_set = user_data;
-
/* Subscriber called unsubscribe */
- if (subscription_data_can_delete (data))
+ if (subscription_data_can_delete ((SubscriptionData *)value))
return;
+ NotifySubscriberData *data = g_new0 (NotifySubscriberData, 1);
+
+ data->data = value;
+ data->property_set = g_bytes_ref ((GBytes *) user_data);
+
/* Create message */
- msg = soup_message_new_from_uri (GENA_METHOD_NOTIFY,
- data->callbacks->data);
+ data->msg = soup_message_new_from_uri (GENA_METHOD_NOTIFY,
+ data->data->callbacks->data);
+
+ SoupMessageHeaders *request_headers = soup_message_get_request_headers (data->msg);
- soup_message_headers_append (msg->request_headers,
+ soup_message_headers_append (request_headers,
"NT",
"upnp:event");
- soup_message_headers_append (msg->request_headers,
+ soup_message_headers_append (request_headers,
"NTS",
"upnp:propchange");
- soup_message_headers_append (msg->request_headers,
+ soup_message_headers_append (request_headers,
"SID",
- data->sid);
+ data->data->sid);
- tmp = g_strdup_printf ("%d", data->seq);
- soup_message_headers_append (msg->request_headers,
+ tmp = g_strdup_printf ("%d", data->data->seq);
+ soup_message_headers_append (request_headers,
"SEQ",
tmp);
g_free (tmp);
/* Handle overflow */
- if (data->seq < G_MAXINT32)
- data->seq++;
+ if (data->data->seq < G_MAXINT32)
+ data->data->seq++;
else
- data->seq = 1;
+ data->data->seq = 1;
/* Add body */
- soup_message_set_request (msg,
+ soup_message_set_request_body_from_bytes (data->msg,
"text/xml; charset=\"utf-8\"",
- SOUP_MEMORY_TAKE,
- g_strdup (property_set),
- strlen (property_set));
+ data->property_set);
/* Queue */
- data->pending_messages = g_list_prepend (data->pending_messages, msg);
- soup_message_headers_append (msg->request_headers,
+ data->data->pending_messages = g_list_prepend (data->data->pending_messages, data->msg);
+ soup_message_headers_append (request_headers,
"Connection", "close");
- session = gupnp_service_get_session (data->service);
+ session = gupnp_service_get_session (data->data->service);
- soup_session_queue_message (session,
- msg,
- notify_got_response,
- data);
+ soup_session_send_and_read_async (session,
+ data->msg,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ (GAsyncReadyCallback) notify_got_response,
+ data);
}
/* Create a property set from @queue */
-static char *
+static GBytes *
create_property_set (GQueue *queue)
{
NotifyData *data;
@@ -2084,28 +2147,27 @@ create_property_set (GQueue *queue)
g_string_append (str, "</e:propertyset>");
/* Cleanup & return */
- return g_string_free (str, FALSE);
+ return g_string_free_to_bytes (str);
}
/* Flush all queued notifications */
static void
flush_notifications (GUPnPService *service)
{
- char *mem;
GUPnPServicePrivate *priv;
priv = gupnp_service_get_instance_private (service);
/* Create property set */
- mem = create_property_set (priv->notify_queue);
+ GBytes *property_set = create_property_set (priv->notify_queue);
/* And send it off */
g_hash_table_foreach (priv->subscriptions,
notify_subscriber,
- mem);
+ property_set);
/* Cleanup */
- g_free (mem);
+ g_bytes_unref (property_set);
}
/**
diff --git a/libgupnp/gupnp-service.h b/libgupnp/gupnp-service.h
index dc47e7d..5ad6c99 100644
--- a/libgupnp/gupnp-service.h
+++ b/libgupnp/gupnp-service.h
@@ -114,7 +114,7 @@ gupnp_service_action_return_error (GUPnPServiceAction *action,
guint error_code,
const char *error_description);
-SoupMessage *
+SoupServerMessage *
gupnp_service_action_get_message (GUPnPServiceAction *action);
guint
diff --git a/libgupnp/gupnp-unix-context-manager.c b/libgupnp/gupnp-unix-context-manager.c
index 180d362..37b7c7b 100644
--- a/libgupnp/gupnp-unix-context-manager.c
+++ b/libgupnp/gupnp-unix-context-manager.c
@@ -30,7 +30,6 @@
#include <arpa/inet.h>
#include <net/if.h>
#include <ifaddrs.h>
-#include <libsoup/soup-address.h>
#include <glib/gstdio.h>
#include <libgssdp/gssdp-error.h>
diff --git a/libgupnp/http-headers.c b/libgupnp/http-headers.c
index cb4e7a6..aa5cdf6 100644
--- a/libgupnp/http-headers.c
+++ b/libgupnp/http-headers.c
@@ -141,7 +141,9 @@ http_request_set_accept_language (SoupMessage *message)
g_free (lang);
- soup_message_headers_append (message->request_headers,
+ SoupMessageHeaders *request_headers = soup_message_get_request_headers (message);
+
+ soup_message_headers_append (request_headers,
"Accept-Language",
tmp->str);
@@ -177,14 +179,14 @@ sort_locales_by_quality (const char *a,
/* Parses the Accept-Language header in @message, and returns its values
* in an ordered list in UNIX locale format */
GList *
-http_request_get_accept_locales (SoupMessage *message)
+http_request_get_accept_locales (SoupMessageHeaders *request_headers)
{
const char *header;
char **bits;
int i;
GList *locales;
- header = soup_message_headers_get_one (message->request_headers,
+ header = soup_message_headers_get_one (request_headers,
"Accept-Language");
if (header == NULL)
return NULL;
@@ -224,7 +226,7 @@ http_request_get_accept_locales (SoupMessage *message)
/* Set Accept-Language header according to @locale. */
void
-http_response_set_content_locale (SoupMessage *msg,
+http_response_set_content_locale (SoupMessageHeaders *response_headers,
const char *locale)
{
char *lang;
@@ -232,7 +234,7 @@ http_response_set_content_locale (SoupMessage *msg,
lang = g_strdup (locale);
http_language_from_locale (lang);
- soup_message_headers_append (msg->response_headers,
+ soup_message_headers_append (response_headers,
"Content-Language",
lang);
@@ -242,7 +244,7 @@ http_response_set_content_locale (SoupMessage *msg,
/* Set Content-Type header guessed from @path, @data and @data_size using
* g_content_type_guess(). */
void
-http_response_set_content_type (SoupMessage *msg,
+http_response_set_content_type (SoupMessageHeaders *response_headers,
const char *path,
const guchar *data,
gsize data_size)
@@ -262,7 +264,7 @@ http_response_set_content_type (SoupMessage *msg,
mime = g_strdup ("text/xml; charset=\"utf-8\"");
}
- soup_message_headers_append (msg->response_headers,
+ soup_message_headers_append (response_headers,
"Content-Type",
mime);
@@ -272,7 +274,7 @@ http_response_set_content_type (SoupMessage *msg,
/* Set Content-Encoding header to gzip and append compressed body */
void
-http_response_set_body_gzip (SoupMessage *msg,
+http_response_set_body_gzip (SoupServerMessage *msg,
const char *body,
const gsize length)
{
@@ -280,7 +282,10 @@ http_response_set_body_gzip (SoupMessage *msg,
gboolean finished = FALSE;
gsize converted = 0;
- soup_message_headers_append (msg->response_headers,
+ SoupMessageBody *message_body = soup_server_message_get_response_body (msg);
+ SoupMessageHeaders *response_headers = soup_server_message_get_response_headers (msg);
+
+ soup_message_headers_append (response_headers,
"Content-Encoding", "gzip");
compressor = g_zlib_compressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP, -1);
@@ -317,7 +322,7 @@ http_response_set_body_gzip (SoupMessage *msg,
}
if (bytes_written)
- soup_message_body_append (msg->response_body,
+ soup_message_body_append (message_body,
SOUP_MEMORY_COPY,
buf, bytes_written);
}
diff --git a/libgupnp/http-headers.h b/libgupnp/http-headers.h
index 5b07a10..846c8c4 100644
--- a/libgupnp/http-headers.h
+++ b/libgupnp/http-headers.h
@@ -23,14 +23,14 @@ G_GNUC_INTERNAL void
http_request_set_accept_language (SoupMessage *message);
G_GNUC_INTERNAL GList *
-http_request_get_accept_locales (SoupMessage *message);
+http_request_get_accept_locales (SoupMessageHeaders *message);
G_GNUC_INTERNAL void
-http_response_set_content_locale (SoupMessage *message,
+http_response_set_content_locale (SoupMessageHeaders *message,
const char *locale);
G_GNUC_INTERNAL void
-http_response_set_content_type (SoupMessage *message,
+http_response_set_content_type (SoupMessageHeaders *response_headers,
const char *path,
const guchar *data,
gsize data_size);
@@ -42,7 +42,7 @@ http_response_set_content_range (SoupMessage *message,
gsize total);
G_GNUC_INTERNAL void
-http_response_set_body_gzip (SoupMessage *msg,
+http_response_set_body_gzip (SoupServerMessage *msg,
const char *body,
const gsize length);
diff --git a/libgupnp/xml-util.c b/libgupnp/xml-util.c
index 6c05668..683a178 100644
--- a/libgupnp/xml-util.c
+++ b/libgupnp/xml-util.c
@@ -93,22 +93,22 @@ xml_util_get_child_element_content_glib (xmlNode *node,
return copy;
}
-SoupURI *
+GUri *
xml_util_get_child_element_content_uri (xmlNode *node,
const char *child_name,
- SoupURI *base)
+ GUri *base)
{
xmlChar *content;
- SoupURI *uri;
+ GUri *uri;
content = xml_util_get_child_element_content (node, child_name);
if (!content)
return NULL;
if (base != NULL)
- uri = soup_uri_new_with_base (base, (const char *) content);
+ uri = g_uri_parse_relative (base, (const char *) content, G_URI_FLAGS_NONE, NULL);
else
- uri = soup_uri_new ((const char *) content);
+ uri = g_uri_parse ((const char *) content, G_URI_FLAGS_NONE, NULL);
xmlFree (content);
@@ -118,18 +118,17 @@ xml_util_get_child_element_content_uri (xmlNode *node,
char *
xml_util_get_child_element_content_url (xmlNode *node,
const char *child_name,
- SoupURI *base)
+ GUri *base)
{
- SoupURI *uri;
+ GUri *uri;
char *url;
uri = xml_util_get_child_element_content_uri (node, child_name, base);
if (!uri)
return NULL;
- url = soup_uri_to_string (uri, FALSE);
-
- soup_uri_free (uri);
+ url = g_uri_to_string_partial (uri, G_URI_HIDE_PASSWORD);
+ g_uri_unref (uri);
return url;
}
diff --git a/libgupnp/xml-util.h b/libgupnp/xml-util.h
index 51d62ba..7078bd6 100644
--- a/libgupnp/xml-util.h
+++ b/libgupnp/xml-util.h
@@ -10,7 +10,6 @@
#define GUPNP_XML_UTIL_H
#include <libxml/tree.h>
-#include <libsoup/soup-uri.h>
#include <stdarg.h>
#include <glib-object.h>
@@ -31,15 +30,15 @@ G_GNUC_INTERNAL char *
xml_util_get_child_element_content_glib (xmlNode *node,
const char *child_name);
-G_GNUC_INTERNAL SoupURI *
+G_GNUC_INTERNAL GUri *
xml_util_get_child_element_content_uri (xmlNode *node,
const char *child_name,
- SoupURI *base);
+ GUri *base);
G_GNUC_INTERNAL char *
xml_util_get_child_element_content_url (xmlNode *node,
const char *child_name,
- SoupURI *base);
+ GUri *base);
G_GNUC_INTERNAL xmlChar *
xml_util_get_attribute_contents (xmlNode *node,
const char *attribute_name);
diff --git a/meson.build b/meson.build
index 68b43f5..0b544e2 100644
--- a/meson.build
+++ b/meson.build
@@ -13,10 +13,10 @@ conf.set('HAVE_NETLINK', netlink_available)
conf.set('HAVE_IFADDRS_H', ifaddrs_available)
conf.set('HAVE_LINUX_WIRELESS_H', cc.has_header('linux/wireless.h'))
-glib_version = '2.66'
+glib_version = '2.69'
add_project_arguments(cc.get_supported_arguments('-Werror=deprecated-declarations'), language: 'c')
-conf.set('GLIB_VERSION_MIN_REQUIRED', 'GLIB_VERSION_' + glib_version.underscorify())
-conf.set('GLIB_VERSION_MAX_ALLOWED', 'GLIB_VERSION_' + glib_version.underscorify())
+conf.set('GLIB_VERSION_MIN_REQUIRED', 'GLIB_VERSION_2_70'.format(glib_version.underscorify()))
+conf.set('GLIB_VERSION_MAX_ALLOWED', 'GLIB_VERSION_2_70'.format(glib_version.underscorify()))
subdir('internal')
guul = subproject('guul', default_options : ['default_library=static'])
@@ -30,7 +30,7 @@ dependencies = [
dependency('gio-2.0', version : '>= ' + glib_version),
dependency('gmodule-2.0', version : '>= ' + glib_version),
dependency('gobject-2.0', version : '>= ' + glib_version),
- dependency('libsoup-2.4', version : '>= 2.48.0'),
+ dependency('libsoup-3.0', version : '>= 2.99.0'),
gssdp_dep,
dependency('libxml-2.0'),
]
diff --git a/tests/test-bugs.c b/tests/test-bugs.c
index 9d118c7..8e8e600 100644
--- a/tests/test-bugs.c
+++ b/tests/test-bugs.c
@@ -163,19 +163,20 @@ test_bgo_690400_query_variable (GUPnPService *service,
}
static gboolean
-test_on_timeout (G_GNUC_UNUSED gpointer user_data)
+test_on_timeout (gpointer user_data)
{
+ g_print ("Timeout in %s\n", (const char *) user_data);
g_assert_not_reached ();
return FALSE;
}
static void
-test_run_loop (GMainLoop *loop)
+test_run_loop (GMainLoop *loop, const char *name)
{
guint timeout_id = 0;
- timeout_id = g_timeout_add_seconds (2, test_on_timeout, NULL);
+ timeout_id = g_timeout_add_seconds (2, test_on_timeout, (gpointer) name);
g_main_loop_run (loop);
g_source_remove (timeout_id);
}
@@ -219,7 +220,7 @@ test_bgo_696762 (void)
G_CALLBACK (test_bgo_696762_on_browse_call),
&data);
- test_run_loop (data.loop);
+ test_run_loop (data.loop, g_test_get_path ());
g_assert (data.proxy != NULL);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
@@ -236,7 +237,7 @@ test_bgo_696762 (void)
NULL);
G_GNUC_END_IGNORE_DEPRECATIONS
- test_run_loop (data.loop);
+ test_run_loop (data.loop, g_test_get_path ());
g_main_loop_unref (data.loop);
g_object_unref (data.proxy);
@@ -287,7 +288,7 @@ test_bgo_678701 (void)
G_CALLBACK (test_bgo_678701_on_dp_available),
&data);
- test_run_loop (data.loop);
+ test_run_loop (data.loop, g_test_get_path ());
g_assert (data.proxy != NULL);
info = gupnp_device_info_get_service (GUPNP_DEVICE_INFO (data.proxy),
@@ -341,7 +342,7 @@ test_bgo_690400 (void)
G_CALLBACK (test_bgo_690400_query_variable), NULL);
gupnp_root_device_set_available (rd, TRUE);
- test_run_loop (data.loop);
+ test_run_loop (data.loop, "690400 - waiting for query_variable");
g_assert (data.proxy != NULL);
gupnp_service_proxy_add_notify (data.proxy,
@@ -357,7 +358,7 @@ test_bgo_690400 (void)
gupnp_service_proxy_set_subscribed (data.proxy, TRUE);
- test_run_loop (data.loop);
+ test_run_loop (data.loop, "690400 - waiting for event");
g_main_loop_unref (data.loop);
g_object_unref (data.proxy);
diff --git a/tests/test-context.c b/tests/test-context.c
index c60ac72..2101328 100644
--- a/tests/test-context.c
+++ b/tests/test-context.c
@@ -25,13 +25,23 @@ create_context (guint16 port, GError **error) {
NULL));
}
+typedef struct {
+ GMainLoop *loop;
+ GBytes *body;
+ GError *error;
+} RangeHelper;
+
+
static void
-on_message_finished (G_GNUC_UNUSED SoupSession *session,
- G_GNUC_UNUSED SoupMessage *message,
- gpointer user_data) {
- GMainLoop *loop = (GMainLoop*) user_data;
+on_message_finished (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ RangeHelper *h = (RangeHelper *)user_data;
+
+ h->body = soup_session_send_and_read_finish (SOUP_SESSION (source), res, &h->error);
- g_main_loop_quit (loop);
+ g_main_loop_quit (h->loop);
}
static void
@@ -50,9 +60,10 @@ request_range_and_compare (GMappedFile *file,
full_length = g_mapped_file_get_length (file);
message = soup_message_new ("GET", uri);
- g_object_ref (message);
- soup_message_headers_set_range (message->request_headers,
+ SoupMessageHeaders *request_headers = soup_message_get_request_headers (message);
+
+ soup_message_headers_set_range (request_headers,
want_start,
want_end);
@@ -71,32 +82,32 @@ request_range_and_compare (GMappedFile *file,
want_length = want_end - want_start + 1;
- soup_session_queue_message (session,
- message,
- on_message_finished,
- loop);
+
+ RangeHelper h = {loop, NULL, NULL};
+ soup_session_send_and_read_async (session, message, G_PRIORITY_DEFAULT, NULL, on_message_finished,
&h);
g_main_loop_run (loop);
- g_assert_cmpint (message->status_code, ==, SOUP_STATUS_PARTIAL_CONTENT);
- g_assert_cmpint (message->response_body->length, ==, want_length);
- got_length = soup_message_headers_get_content_length
- (message->response_headers);
+ g_assert_no_error (h.error);
+ g_assert_nonnull (h.body);
+
+ g_assert_cmpint (soup_message_get_status (message), ==, SOUP_STATUS_PARTIAL_CONTENT);
+ g_assert_cmpint (g_bytes_get_size (h.body), ==, want_length);
+ SoupMessageHeaders *response_headers = soup_message_get_response_headers (message);
+ got_length = soup_message_headers_get_content_length (response_headers);
g_assert_cmpint (got_length, ==, want_length);
- soup_message_headers_get_content_range (message->response_headers,
+ soup_message_headers_get_content_range (response_headers,
&got_start,
&got_end,
&got_length);
g_assert_cmpint (got_start, ==, want_start);
g_assert_cmpint (got_end, ==, want_end);
result = memcmp (g_mapped_file_get_contents (file) + want_start,
- message->response_body->data,
+ g_bytes_get_data (h.body, NULL),
want_length);
g_assert_cmpint (result, ==, 0);
g_object_unref (message);
-
- message = soup_message_new ("GET", uri);
- g_object_ref (message);
+ g_bytes_unref (h.body);
}
static void
@@ -139,6 +150,7 @@ test_gupnp_context_http_ranged_requests (void)
/* Corner cases: First byte */
request_range_and_compare (file, session, loop, uri, 0, 0);
+
/* Corner cases: Last byte */
request_range_and_compare (file,
session,
@@ -170,18 +182,19 @@ test_gupnp_context_http_ranged_requests (void)
/* Try to get 1 byte after the end of the file */
message = soup_message_new ("GET", uri);
- g_object_ref (message);
- soup_message_headers_set_range (message->request_headers,
+ RangeHelper h = {loop, NULL, NULL};
+ soup_message_headers_set_range (soup_message_get_request_headers (message),
file_length,
file_length);
- soup_session_queue_message (session,
- message,
- on_message_finished,
- loop);
+ soup_session_send_and_read_async (session, message, G_PRIORITY_DEFAULT, NULL, on_message_finished,
&h);
g_main_loop_run (loop);
- g_assert_cmpint (message->status_code, ==, SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE);
+
+ g_assert_no_error (h.error);
+ g_assert_nonnull (h.body);
+ g_bytes_unref (h.body);
+ g_assert_cmpint (soup_message_get_status (message), ==, SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE);
g_object_unref (message);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]